<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Markmap</title>
<style>
* {
  margin: 0;
  padding: 0;
}
#mindmap {
  display: block;
  width: 100vw;
  height: 100vh;
}
</style>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.22.0/themes/prism.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/markmap-toolbar@0.1.4/dist/style.min.css">
</head>
<body>
<svg id="mindmap"></svg>
<script src="https://cdn.jsdelivr.net/npm/d3@6.3.0"></script><script src="https://cdn.jsdelivr.net/npm/markmap-view@0.2.0"></script><script src="https://cdn.jsdelivr.net/npm/markmap-toolbar@0.1.4/dist/index.umd.min.js"></script><script>(r => {
                setTimeout(r);
              })(function anonymous(
) {
const toolbar = new markmap.Toolbar();
toolbar.attach(mm);
const el = toolbar.render();
el.setAttribute('style', 'position:absolute;bottom:20px;right:20px');
document.body.append(el);
})</script><script>((getMarkmap, data) => {
        const {
          Markmap
        } = getMarkmap();
        window.mm = Markmap.create('svg#mindmap', null, data);
      })(() => window.markmap,{"t":"heading","d":1,"p":{},"v":"Linux网络编程（BY CHONPSK 2020/12）","c":[{"t":"heading","d":2,"p":{},"v":"网络基础与基本概念","c":[{"t":"heading","d":3,"p":{},"v":"计算机网络概念","c":[{"t":"list_item","d":5,"p":{},"v":"计算机网络：不同地理位置，独立功能的多台<strong>计算机、终端、附属设备</strong>，用<strong>通信设备和通信线路</strong>连接起来，开发相应的<strong>网络软件</strong>实现<strong>资源共享</strong>"},{"t":"list_item","d":5,"p":{},"v":"网络结构组成：","c":[{"t":"list_item","d":7,"p":{},"v":"网络边缘部分：网络应用程序和主机/端系统"},{"t":"list_item","d":7,"p":{},"v":"网络核心部分：路由器、网络构成的网络"},{"t":"list_item","d":7,"p":{},"v":"接入网络和物理介质（接口）：通信链路"},{"t":"list_item","d":7,"p":{},"v":"LAN物理拓扑结构","c":[{"t":"list_item","d":9,"p":{},"v":"总线"},{"t":"list_item","d":9,"p":{},"v":"环形"},{"t":"list_item","d":9,"p":{},"v":"星形"},{"t":"list_item","d":9,"p":{},"v":"扩展星形"},{"t":"list_item","d":9,"p":{},"v":"分层拓扑"},{"t":"list_item","d":9,"p":{},"v":"网格拓扑"}]}]}]},{"t":"heading","d":3,"p":{},"v":"OSI/RM参考模型","c":[{"t":"list_item","d":5,"p":{},"v":"OSI七层模型","c":[{"t":"list_item","d":7,"p":{},"v":"应用层：http,ftp,tftp,smtp,snmp,dns,telnet,https,pop3,dhcp"},{"t":"list_item","d":7,"p":{},"v":"表示层：jpeg,ascii,ebcdic,加密格式等"},{"t":"list_item","d":7,"p":{},"v":"会话层：对应主机进程，指本地主机与远端正在进行的会话"},{"t":"list_item","d":7,"p":{},"v":"传输层：tcp,udp,数据包一旦离开网卡即进入网络传输层"},{"t":"list_item","d":7,"p":{},"v":"网络层：icmp,igmp,ip(v4,v6)地址寻址，不同网络间的路径选择"},{"t":"list_item","d":7,"p":{},"v":"数据链路层：逻辑连接，硬件地址寻址、差错校验。将比特组合成字节进而组合成帧，用mac地址访问介质，错误发现不纠正"},{"t":"list_item","d":7,"p":{},"v":"物理层：TCP/IP层级模型结构，应用层之间的协议通过逐级调用传输层、网络层、链路层而可以实现应用层的应用程序通信互联"}]},{"t":"list_item","d":5,"p":{},"v":"字节序","c":[{"t":"list_item","d":7,"p":{},"v":"大端：低地址-高字节"},{"t":"list_item","d":7,"p":{},"v":"小端：低地址-低字节"}]}]},{"t":"heading","d":3,"p":{},"v":"TCP/IP模型及相关概念","c":[{"t":"list_item","d":5,"p":{},"v":"五层模型","c":[{"t":"list_item","d":7,"p":{},"v":"应用层"},{"t":"list_item","d":7,"p":{},"v":"传输层"},{"t":"list_item","d":7,"p":{},"v":"网络层"},{"t":"list_item","d":7,"p":{},"v":"网络接口（介质）层"}]},{"t":"list_item","d":5,"p":{},"v":"服务指标","c":[{"t":"list_item","d":7,"p":{},"v":"数据丢失率：音频、视频可容忍丢失"},{"t":"list_item","d":7,"p":{},"v":"带宽"},{"t":"list_item","d":7,"p":{},"v":"定时"}]},{"t":"list_item","d":5,"p":{},"v":"应用：Email、web、p2p。。。"},{"t":"list_item","d":5,"p":{},"v":"传输层服务和协议","c":[{"t":"list_item","d":7,"p":{},"v":"运行在端系统"},{"t":"list_item","d":7,"p":{},"v":"两不同主机上运行的应用程序之间的逻辑通信"},{"t":"list_item","d":7,"p":{},"v":"不止一个传输层协议可以用于应用程序"},{"t":"list_item","d":7,"p":{},"v":"tcp、udp"}]},{"t":"list_item","d":5,"p":{},"v":"网络层","c":[{"t":"list_item","d":7,"p":{},"v":"发送方封装数据成组"},{"t":"list_item","d":7,"p":{},"v":"将分组从发送方送到接受方"},{"t":"list_item","d":7,"p":{},"v":"解包后递交给传输层"},{"t":"list_item","d":7,"p":{},"v":"所以路由和主机都有网络层协议"},{"t":"list_item","d":7,"p":{},"v":"路由器检查所有经过它的ip分组的分组头"}]},{"t":"list_item","d":5,"p":{},"v":"网络层的重要功能","c":[{"t":"list_item","d":7,"p":{},"v":"选路：决定分组从源端到目的端所经过的路径","c":[{"t":"list_item","d":9,"p":{},"v":"选路算法"}]},{"t":"list_item","d":7,"p":{},"v":"转发：路由器将收到的分组移动到适当的输出链路"},{"t":"list_item","d":7,"p":{},"v":"术语","c":[{"t":"list_item","d":9,"p":{},"v":"routing：决定分组从源端到目的端所经历过路径的过程"},{"t":"list_item","d":9,"p":{},"v":"forwarding：将分组从一个输入链路接口转移到适当输出链路接口的过程"}]},{"t":"list_item","d":7,"p":{},"v":"通过路由连接的两个网络（实例）","c":[{"t":"list_item","d":9,"p":{},"v":"<img src=\"./tcpIp_1.png\" alt=\"image-20201220093709518\">"}]},{"t":"list_item","d":7,"p":{},"v":"数据进入协议栈时的封装","c":[{"t":"list_item","d":9,"p":{},"v":"<img src=\"./tcpIp_2.png\" alt=\"image-data\">"}]},{"t":"list_item","d":7,"p":{},"v":"UDP:用户数据报协议","c":[{"t":"list_item","d":9,"p":{},"v":"无连接服务"},{"t":"list_item","d":9,"p":{},"v":"缺乏可靠性支持，应用程序必须实现：确认、超时、重传、流控。。"},{"t":"list_item","d":9,"p":{},"v":"面向记录服务"},{"t":"list_item","d":9,"p":{},"v":"数据报格式","c":[{"t":"list_item","d":11,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">ifdef</span> <span class=\"token expression\">__FAVOR_BSD</span></span>\n<span class=\"token keyword\">struct</span> <span class=\"token class-name\">udphdr</span> <span class=\"token punctuation\">{</span>\n         u_int16_t uh_sport<span class=\"token punctuation\">;</span>           <span class=\"token comment\">/* source port */</span>\n         u_int16_t uh_dport<span class=\"token punctuation\">;</span>           <span class=\"token comment\">/* destination port */</span>\n         u_int16_t uh_ulen<span class=\"token punctuation\">;</span>            <span class=\"token comment\">/* udp length */</span>\n         u_int16_t uh_sum<span class=\"token punctuation\">;</span>             <span class=\"token comment\">/* udp checksum */</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n<span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">else</span></span>\n</code></pre>\n"},{"t":"list_item","d":11,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">struct</span> <span class=\"token class-name\">udphdr</span> <span class=\"token punctuation\">{</span>\n  u_int16_t     source<span class=\"token punctuation\">;</span>\n  u_int16_t     dest<span class=\"token punctuation\">;</span>\n  u_int16_t     len<span class=\"token punctuation\">;</span>\n  u_int16_t     check<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n<span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">endif</span></span>\n</code></pre>\n"}]}]},{"t":"list_item","d":7,"p":{},"v":"TCP：传输控制协议","c":[{"t":"list_item","d":9,"p":{},"v":"面向连接"},{"t":"list_item","d":9,"p":{},"v":"提供可靠性，实现了丢失重传。RTT估算"},{"t":"list_item","d":9,"p":{},"v":"通过给所发数据的每一个段管理一个序列号进行排序"},{"t":"list_item","d":9,"p":{},"v":"提供流量控制和拥塞控制：通告窗口、拥塞窗口"},{"t":"list_item","d":9,"p":{},"v":"全双工"},{"t":"list_item","d":9,"p":{},"v":"概述","c":[{"t":"list_item","d":11,"p":{},"v":"点到点：一发送者，一接收者"},{"t":"list_item","d":11,"p":{},"v":"可靠按序的字节流：无信息边界，流式传输。<strong>注意缓冲区操作</strong>"},{"t":"list_item","d":11,"p":{},"v":"流水线：tcp拥塞和流量控制设置窗口大小"},{"t":"list_item","d":11,"p":{},"v":"收发缓冲区"},{"t":"list_item","d":11,"p":{},"v":"全双工：最大传输单元，最大分段大小"},{"t":"list_item","d":11,"p":{},"v":"面向连接"},{"t":"list_item","d":11,"p":{},"v":"流量控制"}]},{"t":"list_item","d":9,"p":{},"v":"序号和确认","c":[{"t":"list_item","d":11,"p":{},"v":"三次握手"},{"t":"list_item","d":11,"p":{},"v":"四次挥手（很少用）"}]},{"t":"list_item","d":9,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">struct</span> <span class=\"token class-name\">tcphdr</span> <span class=\"token punctuation\">{</span>   \n    WORD  SourPort<span class=\"token punctuation\">;</span>   \n    WORD  DestPort<span class=\"token punctuation\">;</span>\n    DWORD     SeqNo<span class=\"token punctuation\">;</span>\n    DWORD     AckNo<span class=\"token punctuation\">;</span>\n    BYTE  HLen<span class=\"token punctuation\">;</span>   \n    BYTE  Flag<span class=\"token punctuation\">;</span>\n    WORD  Window<span class=\"token punctuation\">;</span>\n    WORD  ChkSum<span class=\"token punctuation\">;</span>\n    WORD  UrgPtr<span class=\"token punctuation\">;</span>\n    <span class=\"token comment\">/* Put options here. */</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span> \n\n</code></pre>\n"},{"t":"list_item","d":9,"p":{},"v":"连接的建立","c":[{"t":"list_item","d":11,"p":{},"v":"服务器接受外来连接：socket,bing,listen被动打开"},{"t":"list_item","d":11,"p":{},"v":"客户端调用connect主动打开，发生syn分节，告诉服务器发送的数据的初始序列号"},{"t":"list_item","d":11,"p":{},"v":"服务器确定syn，发送自己syn，对客户端syn发ack"},{"t":"list_item","d":11,"p":{},"v":"客户确认服务器syn"}]}]},{"t":"list_item","d":7,"p":{},"v":"地址","c":[{"t":"list_item","d":9,"p":{},"v":"物理地址：MAC","c":[{"t":"list_item","d":11,"p":{},"v":"48位，24OUI,24厂商分配"},{"t":"list_item","d":11,"p":{},"v":"全球唯一"},{"t":"list_item","d":11,"p":{},"v":"局部范围寻址"},{"t":"list_item","d":11,"p":{},"v":"存在数据链路层"}]},{"t":"list_item","d":9,"p":{},"v":"逻辑地址：IP地址","c":[{"t":"list_item","d":11,"p":{},"v":"32/128位"},{"t":"list_item","d":11,"p":{},"v":"分为网络号、主机号。"},{"t":"list_item","d":11,"p":{},"v":"全球唯一"},{"t":"list_item","d":11,"p":{},"v":"二进制、点分十进制"},{"t":"list_item","d":11,"p":{},"v":"A,B,C,D类"},{"t":"list_item","d":11,"p":{},"v":"寻址","c":[{"t":"list_item","d":13,"p":{},"v":"ip：分配给主机/路由器接口的32bit标识符"},{"t":"list_item","d":13,"p":{},"v":"接口：主机/路由器与物理链路之间的边界","c":[{"t":"list_item","d":15,"p":{},"v":"主机可以有多个接口"},{"t":"list_item","d":15,"p":{},"v":"路由可以有多个接口"},{"t":"list_item","d":15,"p":{},"v":"每个接口一个IP"}]}]}]},{"t":"list_item","d":9,"p":{},"v":"端口地址：端口号"},{"t":"list_item","d":9,"p":{},"v":"域名地址：网址"},{"t":"list_item","d":9,"p":{},"v":"局域网地址：每一个适配器有一个唯一的LAN地址"}]},{"t":"list_item","d":7,"p":{},"v":"应用层：主机名，网络层IP地址，链路层MAC地址。有利于保持各层独立的原则"}]},{"t":"list_item","d":5,"p":{},"v":"子网","c":[{"t":"list_item","d":7,"p":{},"v":"IP地址高位为子网部分"},{"t":"list_item","d":7,"p":{},"v":"ip网络号相同为同一子网"},{"t":"list_item","d":7,"p":{},"v":"没有路由介入，物理上能相互到达"},{"t":"list_item","d":7,"p":{},"v":"分离的网络岛，独立的网络为一个子网"},{"t":"list_item","d":7,"p":{},"v":"子网掩码过滤子网号留下主机号"}]},{"t":"list_item","d":5,"p":{},"v":"端口地址","c":[{"t":"list_item","d":7,"p":{},"v":"tcp&amp;&amp;udp使用16位端口号，房子使用混乱","c":[{"t":"list_item","d":9,"p":{},"v":"0~1023：lana统一控制"},{"t":"list_item","d":9,"p":{},"v":"1024~49151：注册端口"},{"t":"list_item","d":9,"p":{},"v":"动态或私有的端口地址：49152~65535"}]}]},{"t":"list_item","d":5,"p":{},"v":"网络中通信双方由四元组唯一确定","c":[{"t":"list_item","d":7,"p":{},"v":"本地IP地址"},{"t":"list_item","d":7,"p":{},"v":"本地端口号"},{"t":"list_item","d":7,"p":{},"v":"远程IP地址"},{"t":"list_item","d":7,"p":{},"v":"远程端口号"}]},{"t":"list_item","d":5,"p":{},"v":"DNS：域名地址","c":[{"t":"list_item","d":7,"p":{},"v":"层次名字空间"},{"t":"list_item","d":7,"p":{},"v":"便于记忆和使用"},{"t":"list_item","d":7,"p":{},"v":"计算机通信时无法使用"},{"t":"list_item","d":7,"p":{},"v":"名字-ip地址的解析：gethostbyname"},{"t":"list_item","d":7,"p":{},"v":"ip到域名的解析：gethostbyaddr"},{"t":"list_item","d":7,"p":{},"v":"分布式数据库"},{"t":"list_item","d":7,"p":{},"v":"应用层协"}]}]},{"t":"heading","d":3,"p":{},"v":"构建分布式应用程序","c":[{"t":"list_item","d":5,"p":{},"v":"网络技术已日渐成为所有软件的一部分"},{"t":"list_item","d":5,"p":{},"v":"必须掌握的知识：设计和实现分布式应用程序所用到的原则和技术"},{"t":"list_item","d":5,"p":{},"v":"分布式计算的一个主要目标：透明性","c":[{"t":"list_item","d":7,"p":{},"v":"隐藏计算机和服务的地理位置"}]},{"t":"list_item","d":5,"p":{},"v":"标准的应用层协议","c":[{"t":"list_item","d":7,"p":{},"v":"tcp/ip协议族"},{"t":"list_item","d":7,"p":{},"v":"文件传送，电子邮件，远程登陆"}]},{"t":"list_item","d":5,"p":{},"v":"非标准的应用层协议","c":[{"t":"list_item","d":7,"p":{},"v":"使用tcp/ip进行通信的程序"},{"t":"list_item","d":7,"p":{},"v":"标准化之后，会成为标准协议例如"}]},{"t":"list_item","d":5,"p":{},"v":"telnet：标准应用协议"},{"t":"list_item","d":5,"p":{},"v":"应用协议与软件灵活性","c":[{"t":"list_item","d":7,"p":{},"v":"协议的设计基于多种应用的*<em>基本抽象</em>"},{"t":"list_item","d":7,"p":{},"v":"实现服务时尽可能用标准应用协议通信"}]}]},{"t":"heading","d":3,"p":{},"v":"客户/服务器模型及原理","c":[{"t":"list_item","d":5,"p":{},"v":"体系结构","c":[{"t":"list_item","d":7,"p":{},"v":"服务器","c":[{"t":"list_item","d":9,"p":{},"v":"常开"},{"t":"list_item","d":9,"p":{},"v":"固定，周知的ip地址"},{"t":"list_item","d":9,"p":{},"v":"主机集群集常被用于创建强大的虚拟服务器"}]},{"t":"list_item","d":7,"p":{},"v":"客户机：","c":[{"t":"list_item","d":9,"p":{},"v":"同服务器端通信"},{"t":"list_item","d":9,"p":{},"v":"间断连接服务器"},{"t":"list_item","d":9,"p":{},"v":"动态ip"},{"t":"list_item","d":9,"p":{},"v":"c-c不直接通信"}]}]},{"t":"list_item","d":5,"p":{},"v":"C/S模型","c":[{"t":"list_item","d":7,"p":{},"v":"符合现实生活习惯"},{"t":"list_item","d":7,"p":{},"v":"TCP/IP仅仅时传输数据的<strong>基本机制</strong>"},{"t":"list_item","d":7,"p":{},"v":"主要解决<strong>通信会聚</strong>问题","c":[{"t":"list_item","d":9,"p":{},"v":"同一时刻双方互发消息通信不可靠"},{"t":"list_item","d":9,"p":{},"v":"通信一方启动执行后一直等待对方的联系更加可靠"},{"t":"list_item","d":9,"p":{},"v":"下层协议不必对收到的信息进行响应，减少下层协议的复杂性"}]}]},{"t":"list_item","d":5,"p":{},"v":"术语和概念","c":[{"t":"list_item","d":7,"p":{},"v":"通信发起方向区分","c":[{"t":"list_item","d":9,"p":{},"v":"客户client：发起对等通信的应用程序","c":[{"t":"list_item","d":11,"p":{},"v":"没次执行都与服务器联系"},{"t":"list_item","d":11,"p":{},"v":"容易构建，往往不需要系统特权"},{"t":"list_item","d":11,"p":{},"v":"属于常规网络应用程序"},{"t":"list_item","d":11,"p":{},"v":"参数化","c":[{"t":"list_item","d":13,"p":{},"v":"提高通用性"},{"t":"list_item","d":13,"p":{},"v":"指定s地址，s端口"},{"t":"list_item","d":13,"p":{},"v":"远程主机地址"},{"t":"list_item","d":13,"p":{},"v":"端口号"},{"t":"list_item","d":13,"p":{},"v":"其他可选参数"},{"t":"list_item","d":13,"p":{},"v":"便于测试"}]}]},{"t":"list_item","d":9,"p":{},"v":"服务器server：等待接受客户通信请求的程序","c":[{"t":"list_item","d":11,"p":{},"v":"接受客户请求"},{"t":"list_item","d":11,"p":{},"v":"执行必要操作"},{"t":"list_item","d":11,"p":{},"v":"返回结果给客户"},{"t":"list_item","d":11,"p":{},"v":"特权与复杂性","c":[{"t":"list_item","d":13,"p":{},"v":"需要访问受操作系统保护的资源：需要系统特权"},{"t":"list_item","d":13,"p":{},"v":"不能把特权给客户"},{"t":"list_item","d":13,"p":{},"v":"需要处理的安全问题","c":[{"t":"list_item","d":15,"p":{},"v":"鉴别：客户身份"},{"t":"list_item","d":15,"p":{},"v":"授权：c是否可以使用服务器提供的服务"},{"t":"list_item","d":15,"p":{},"v":"数据安全：数据不被无意泄露、损坏"},{"t":"list_item","d":15,"p":{},"v":"保密：防止未经授权访问信息"},{"t":"list_item","d":15,"p":{},"v":"保护：确报网络程序不能滥用系统资源"}]}]},{"t":"list_item","d":11,"p":{},"v":"特权与并发导致了服务器软件复杂性"}]}]},{"t":"list_item","d":7,"p":{},"v":"无连接/面向连接的服务器","c":[{"t":"list_item","d":9,"p":{},"v":"udp","c":[{"t":"list_item","d":11,"p":{},"v":"无可靠保证"},{"t":"list_item","d":11,"p":{},"v":"依赖下层系统保证"},{"t":"list_item","d":11,"p":{},"v":"程序中应该有相应保障措施"}]},{"t":"list_item","d":9,"p":{},"v":"tcp","c":[{"t":"list_item","d":11,"p":{},"v":"传输可靠"},{"t":"list_item","d":11,"p":{},"v":"程序要求简单"}]},{"t":"list_item","d":9,"p":{},"v":"upd场景","c":[{"t":"list_item","d":11,"p":{},"v":"下层系统可靠性（局域网）"},{"t":"list_item","d":11,"p":{},"v":"应用不需要额外可靠处理"},{"t":"list_item","d":11,"p":{},"v":"广播/组播"}]}]},{"t":"list_item","d":7,"p":{},"v":"一个主机可以是服务器，也可以是客户。服务a基于服务b提供给客户c","c":[{"t":"list_item","d":9,"p":{},"v":"时间服务器-》文件服务器-》客户"}]}]}]}]},{"t":"heading","d":2,"p":{},"v":"c/s软件中的并发处理","c":[{"t":"heading","d":3,"p":{},"v":"并发的概念","c":[{"t":"list_item","d":5,"p":{},"v":"并发有真正并发（并行）和表面并发（并发，分时机制）"}]},{"t":"heading","d":3,"p":{},"v":"网络中的并发","c":[{"t":"list_item","d":4,"p":{},"v":"单网络各机器间，许多成对进程好像独立使用网络资源"},{"t":"list_item","d":4,"p":{},"v":"计算机系统中存在并发（分时）"},{"t":"list_item","d":4,"p":{},"v":"一组机器上所有客户之间存在并发"},{"t":"list_item","d":4,"p":{},"v":"机器中各客户，一组机器上所有客户之间也可存在并发","c":[{"t":"list_item","d":6,"p":{},"v":"不需要特地实现，一般操作系统已经支持"}]}]},{"t":"heading","d":3,"p":{},"v":"服务器并发","c":[{"t":"list_item","d":4,"p":{},"v":"单服务器必须并发处理多个传入请求"},{"t":"list_item","d":4,"p":{},"v":"多个远端c使用同一个服务，实现较复杂"}]},{"t":"heading","d":3,"p":{},"v":"操作系统并发","c":[{"t":"list_item","d":4,"p":{},"v":"多进程os"},{"t":"list_item","d":4,"p":{},"v":"进程：定义了一个计算的基本单元，它是一个执行某一个特定程序的实体，<strong>拥有独立地址空间、执行堆栈、文件描述符。。。</strong>"},{"t":"list_item","d":4,"p":{},"v":"os通过执行的线程间快速切换cpu，使得计算机好似同时执行多个运算"},{"t":"list_item","d":4,"p":{},"v":"创建进程","c":[{"t":"list_item","d":6,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">include</span> <span class=\"token string\">&lt;sys/types.h></span></span>\n<span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">include</span> <span class=\"token string\">&lt;unistd.h></span></span>\npid_t <span class=\"token function\">fork</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span><span class=\"token comment\">//fork创建子进程</span>\n<span class=\"token comment\">//返回：</span>\n    <span class=\"token comment\">//父进程中返回子进程的进程ID</span>\n    <span class=\"token comment\">//子进程返回0</span>\n    <span class=\"token comment\">//出错返回-1</span>\n</code></pre>\n"},{"t":"list_item","d":6,"p":{},"v":"父子进程共享数据空间、代码空间、堆栈、所有的文件描述子；但相互之间互不影响"}]},{"t":"list_item","d":4,"p":{},"v":"程序并发实例","c":[{"t":"list_item","d":6,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">include</span> <span class=\"token string\">&lt;stdlib.h></span></span>\n<span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">include</span> <span class=\"token string\">&lt;stdio.h></span></span>\n<span class=\"token keyword\">int</span> sum<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">int</span> <span class=\"token function\">main</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">int</span> i<span class=\"token punctuation\">;</span>\n    sum <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">fork</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> ； <span class=\"token comment\">//建立并发</span>\n    <span class=\"token keyword\">for</span><span class=\"token punctuation\">(</span>i<span class=\"token operator\">=</span><span class=\"token number\">1</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">&lt;=</span><span class=\"token number\">5</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span><span class=\"token comment\">//由于共享空间，所有父子进行都执行以下代码</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"The value of i is %d\\n\"</span><span class=\"token punctuation\">,</span>i<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token function\">fflush</span><span class=\"token punctuation\">(</span><span class=\"token constant\">stdout</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        sum <span class=\"token operator\">+=</span> i<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"The sum is %d\\n\"</span><span class=\"token punctuation\">,</span>sum<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">exit</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token comment\">//fork以下的代码会被执行2次，但由于操作过少，计算机效率过高，在一个进程时间内就把上述代码执行完了，所有实际运行时，表现得先后执行了，循环加到1000？</span>\n</code></pre>\n"},{"t":"list_item","d":6,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">include</span> <span class=\"token string\">&lt;stdlib.h></span></span>\n<span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">include</span> <span class=\"token string\">&lt;stdio.h></span></span>\n<span class=\"token keyword\">int</span> mul<span class=\"token punctuation\">,</span>sum<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">int</span> <span class=\"token function\">main</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">int</span> i<span class=\"token punctuation\">,</span>pid<span class=\"token punctuation\">;</span>\n    sum <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\n    mul <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>pid<span class=\"token operator\">=</span><span class=\"token function\">fork</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">></span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>    <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">for</span><span class=\"token punctuation\">(</span>i<span class=\"token operator\">=</span><span class=\"token number\">1</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">&lt;=</span><span class=\"token number\">5</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span>     <span class=\"token punctuation\">{</span>\n            <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"The value of i is %d\\n\"</span><span class=\"token punctuation\">,</span>i<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token function\">fflush</span><span class=\"token punctuation\">(</span><span class=\"token constant\">stdout</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            sum <span class=\"token operator\">+=</span> i<span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"The sum is %d\\n\"</span><span class=\"token punctuation\">,</span>sum<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">else</span> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>pid <span class=\"token operator\">==</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>    <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span>i<span class=\"token operator\">=</span><span class=\"token number\">1</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">&lt;=</span><span class=\"token number\">5</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span>        <span class=\"token punctuation\">{</span>\n            <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"The value of i is %d\\n\"</span><span class=\"token punctuation\">,</span>i<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token function\">fflush</span><span class=\"token punctuation\">(</span><span class=\"token constant\">stdout</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            mul <span class=\"token operator\">*=</span> i<span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"The multiplex is %d\\n\"</span><span class=\"token punctuation\">,</span>mul<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n   <span class=\"token function\">exit</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token comment\">//通过这段代码我们发现，多进程会先运行子进程，然后运行父进程。所以时先乘后加</span>\n</code></pre>\n"}]},{"t":"list_item","d":4,"p":{},"v":"执行新的代码","c":[{"t":"list_item","d":6,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">＃include <span class=\"token operator\">&lt;</span>unistd<span class=\"token punctuation\">.</span>h<span class=\"token operator\">></span>\n<span class=\"token keyword\">int</span> <span class=\"token function\">execl</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">const</span> <span class=\"token keyword\">char</span> <span class=\"token operator\">*</span>path<span class=\"token punctuation\">,</span> <span class=\"token keyword\">const</span> <span class=\"token keyword\">char</span> <span class=\"token operator\">*</span>arg<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">.</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">//系统调用execl执行另一个程序。但调用execl并不创建新进程，所以前后的进程ID并未改变，execl只是用另一个新程序替换了当前进程的正文、数据、段和堆栈；</span>\n    <span class=\"token comment\">//path为要执行的二进制文件或脚本的完整路径</span>\n    <span class=\"token comment\">//argv时要传给程序的完整参数列表，包括arg[0],一般是执行程序的名字</span>\n    <span class=\"token comment\">//命令行参数</span>\n    <span class=\"token comment\">//最后一个参数可为NULL</span>\n</code></pre>\n"},{"t":"list_item","d":6,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> mul<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">int</span> <span class=\"token function\">main</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">int</span> i<span class=\"token punctuation\">,</span>pid<span class=\"token punctuation\">;</span><span class=\"token comment\">//pid:进程号</span>\n    mul <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>pid<span class=\"token operator\">=</span><span class=\"token function\">fork</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">></span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token comment\">//开子进程</span>\n        <span class=\"token function\">execl</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"./sum\"</span><span class=\"token punctuation\">,</span><span class=\"token string\">\"./sum\"</span><span class=\"token punctuation\">,</span><span class=\"token constant\">NULL</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><span class=\"token comment\">//进sum</span>\n    <span class=\"token keyword\">else</span> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>pid <span class=\"token operator\">==</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>    <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span>i<span class=\"token operator\">=</span><span class=\"token number\">1</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">&lt;=</span><span class=\"token number\">5</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span>   <span class=\"token punctuation\">{</span><span class=\"token comment\">//父进程为乘</span>\n            <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"The value of i is %d\\n\"</span><span class=\"token punctuation\">,</span>i<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token function\">fflush</span><span class=\"token punctuation\">(</span><span class=\"token constant\">stdout</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            mul <span class=\"token operator\">*=</span> i<span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"The multiplex is %d\\n\"</span><span class=\"token punctuation\">,</span>mul<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">else</span>\n        <span class=\"token function\">exit</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">exit</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token comment\">//结果与上述代码无异</span>\n</code></pre>\n"}]},{"t":"list_item","d":4,"p":{},"v":"上下文切换","c":[{"t":"list_item","d":6,"p":{},"v":"OS时间分片机制保证快速切换"},{"t":"list_item","d":6,"p":{},"v":"线程切换的时候，会发生上下文切换","c":[{"t":"list_item","d":8,"p":{},"v":"上下文：线程的执行环境"},{"t":"list_item","d":8,"p":{},"v":"切换有开销"}]},{"t":"list_item","d":6,"p":{},"v":"设计协议软件时，尽可能减少上下文切换次数","c":[{"t":"list_item","d":8,"p":{},"v":"保证并发的效率大于上下文切换的开销"},{"t":"list_item","d":8,"p":{},"v":"非并发，单线程进程并发，多线程进程并发"}]}]},{"t":"list_item","d":4,"p":{},"v":"并发与异步I/O","c":[{"t":"list_item","d":6,"p":{},"v":"某些os允许单线程控制并发的输入输出操作"},{"t":"list_item","d":6,"p":{},"v":"线程使用select询问操作系统io设备的情况","c":[{"t":"list_item","d":8,"p":{},"v":"用户从tcp和键盘接受输入"},{"t":"list_item","d":8,"p":{},"v":"若单独等待会产生阻塞，使用select轮询输入就绪可以避免"}]}]},{"t":"list_item","d":4,"p":{},"v":"fflush函数","c":[{"t":"list_item","d":6,"p":{},"v":"输出流-把流缓冲区的内容写到和这个流关联的文件"},{"t":"list_item","d":6,"p":{},"v":"输入流，就把和输入关联的流缓冲区的内容清除"},{"t":"list_item","d":6,"p":{},"v":"只对缓冲区流有用，对unbuffered stream无影响"}]}]}]},{"t":"heading","d":2,"p":{},"v":"协议的程序接口","c":[{"t":"heading","d":3,"p":{},"v":"不精确指明的协议软件接口","c":[{"t":"list_item","d":5,"p":{},"v":"TCP/IP协议存在与OS中，网络服务通过OS提供"},{"t":"list_item","d":5,"p":{},"v":"要和不同的机器兼容，TCP/IP尽量避免使用任何一家厂商的内部数据表示"},{"t":"list_item","d":5,"p":{},"v":"TCP/IP和应用程序之间的接口应该时不精确指明的：","c":[{"t":"list_item","d":7,"p":{},"v":"不规定接口的细节"},{"t":"list_item","d":7,"p":{},"v":"只建议需要的功能集"},{"t":"list_item","d":7,"p":{},"v":"允许系统设计者选择有关API的具体实现细节"}]},{"t":"list_item","d":5,"p":{},"v":"优点：提供了灵活性和容错能力","c":[{"t":"list_item","d":7,"p":{},"v":"便于各种OS实现TCP/IP"},{"t":"list_item","d":7,"p":{},"v":"接口可以是过程的，也可以是消息的"}]},{"t":"list_item","d":5,"p":{},"v":"缺点：不同的OS中，接口细节不同","c":[{"t":"list_item","d":7,"p":{},"v":"移植性差"},{"t":"list_item","d":7,"p":{},"v":"程序员需要重新学习接口知识"}]},{"t":"list_item","d":5,"p":{},"v":"举例","c":[{"t":"list_item","d":7,"p":{},"v":"Berkeley UNIX的套接字接口"},{"t":"list_item","d":7,"p":{},"v":"Microsoft Windows 的 windows socket"},{"t":"list_item","d":7,"p":{},"v":"AT&amp;T的UNIX系统V的TLI"}]},{"t":"list_item","d":5,"p":{},"v":"接口功能","c":[{"t":"list_item","d":7,"p":{},"v":"分配用于通信的本地资源"},{"t":"list_item","d":7,"p":{},"v":"指定本地和远程通信端点"},{"t":"list_item","d":7,"p":{},"v":"c：启动连接"},{"t":"list_item","d":7,"p":{},"v":"c：发送数据报"},{"t":"list_item","d":7,"p":{},"v":"s：等待连接到来"},{"t":"list_item","d":7,"p":{},"v":"发送或接受数据"},{"t":"list_item","d":7,"p":{},"v":"判断数据何时到达"},{"t":"list_item","d":7,"p":{},"v":"产生紧急数据"},{"t":"list_item","d":7,"p":{},"v":"处理到来的紧急数据"},{"t":"list_item","d":7,"p":{},"v":"从容终止连接"},{"t":"list_item","d":7,"p":{},"v":"处理来自远程端点的连接终止"},{"t":"list_item","d":7,"p":{},"v":"异常终止通信"},{"t":"list_item","d":7,"p":{},"v":"处理错误条件或者连接异常终止"},{"t":"list_item","d":7,"p":{},"v":"连接结束后释放本地资源"}]}]},{"t":"heading","d":3,"p":{},"v":"概念性接口规约","c":[{"t":"list_item","d":5,"p":{},"v":"概念性接口：","c":[{"t":"list_item","d":7,"p":{},"v":"提供示例"},{"t":"list_item","d":7,"p":{},"v":"一组过程和函数（控制权：程序-》函数），和他们要求的参数和操作的语义，eg. send"},{"t":"list_item","d":7,"p":{},"v":"不指明数据的表示和编程细节"},{"t":"list_item","d":7,"p":{},"v":"由OS实现成为API"},{"t":"list_item","d":7,"p":{},"v":"只要求功能相同，可以自由选择过程名和参数"}]}]},{"t":"heading","d":3,"p":{},"v":"系统调用","c":[{"t":"list_item","d":5,"p":{},"v":"应用程序和os之间传递控制权（函数调用）"},{"t":"list_item","d":5,"p":{},"v":"目的是从os获得服务"},{"t":"list_item","d":5,"p":{},"v":"一定的权限控制（允许读取或修改操作系统数据结构）"},{"t":"list_item","d":5,"p":{},"v":"流程结构：<img src=\"./tcpIp_3.png\" alt=\"os\">"}]},{"t":"heading","d":3,"p":{},"v":"网络通信的两种基本方法","c":[{"t":"list_item","d":5,"p":{},"v":"使用新的系统调用来访问TCP/ip","c":[{"t":"list_item","d":7,"p":{},"v":"对于每个概念性的操作实现一个系统调用"},{"t":"list_item","d":7,"p":{},"v":"创建新的系统调用并不明智"}]},{"t":"list_item","d":5,"p":{},"v":"使用一般的I/O调用来访问TCP/IP","c":[{"t":"list_item","d":7,"p":{},"v":"使用一般的I/O调用，但是进行了扩充，既可用于I/O，又可以用于网络协议"}]},{"t":"list_item","d":5,"p":{},"v":"混合方法","c":[{"t":"list_item","d":7,"p":{},"v":"尽可能使用基本的io功能"},{"t":"list_item","d":7,"p":{},"v":"增加一些函数来实现其它操作"}]}]},{"t":"heading","d":3,"p":{},"v":"LINUX中提供的基本I/O功能","c":[{"t":"list_item","d":5,"p":{},"v":"理解基本I/O如何扩展功能，六个基本的系统函数","c":[{"t":"list_item","d":7,"p":{},"v":"open：为io操作准备一个设备或者文件"},{"t":"list_item","d":7,"p":{},"v":"close：终止使用以前已打开的设备/文件"},{"t":"list_item","d":7,"p":{},"v":"read：从输入设备/文件中得到数据"},{"t":"list_item","d":7,"p":{},"v":"write：数据从apg存储器传到设备/文件中"},{"t":"list_item","d":7,"p":{},"v":"Lseek：转到文件/设备中的某个指定位置"},{"t":"list_item","d":7,"p":{},"v":"Loctl：控制设备或者用于访问该设备的软件"}]},{"t":"list_item","d":5,"p":{},"v":"基本I/O举例","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> desc\ndesc<span class=\"token operator\">=</span><span class=\"token function\">open</span><span class=\"token punctuation\">(</span>“filename”<span class=\"token punctuation\">,</span> O_RDWR<span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n<span class=\"token comment\">//打开filename路径，以读写方式，将句柄给desc0</span>\n<span class=\"token function\">read</span><span class=\"token punctuation\">(</span>desc<span class=\"token punctuation\">,</span>buffer<span class=\"token punctuation\">,</span><span class=\"token number\">128</span><span class=\"token punctuation\">)</span>\n<span class=\"token comment\">//将desc中读128到buffer</span>\n<span class=\"token function\">close</span><span class=\"token punctuation\">(</span>desc<span class=\"token punctuation\">)</span>\n<span class=\"token comment\">//结束filename文件范围</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"将LinuxI/O用于TCP/IP","c":[{"t":"list_item","d":7,"p":{},"v":"扩展文件描述符：可以用于网络通信"},{"t":"list_item","d":7,"p":{},"v":"扩展read和write：可以用于网络标识符"},{"t":"list_item","d":7,"p":{},"v":"额外功能的处理，增加新系统调用","c":[{"t":"list_item","d":9,"p":{},"v":"指明本地和远端的端口，远程IP地址"},{"t":"list_item","d":9,"p":{},"v":"使用TCP/UDP"},{"t":"list_item","d":9,"p":{},"v":"启动传输/等待接入"},{"t":"list_item","d":9,"p":{},"v":"可以接受多少传入连接"},{"t":"list_item","d":9,"p":{},"v":"传输UDP数据"}]}]}]}]},{"t":"heading","d":2,"p":{},"v":"套接字API","c":[{"t":"heading","d":3,"p":{},"v":"套接字","c":[{"t":"list_item","d":5,"p":{},"v":"TCP/IP协议存在于OS中，网络服务通过OS提供"},{"t":"list_item","d":5,"p":{},"v":"在OS中增加支持TCP/IP的系统调用即Berkeley套接字"},{"t":"list_item","d":5,"p":{},"v":"socket，connect，send，recv都是其中的接口"},{"t":"list_item","d":5,"p":{},"v":"一个主机本地应用程序所创建，为操作系统所控制的接口（“门”）"},{"t":"list_item","d":5,"p":{},"v":"应用进程通过这个接口，使用传输层提供的服务，跨网络发送/接受消息到/从，其他应用进程"},{"t":"list_item","d":5,"p":{},"v":"c/s模式的通信接口-套接字接口"},{"t":"list_item","d":5,"p":{},"v":"创建一个应用程序使用进行网络通信的接口"},{"t":"list_item","d":5,"p":{},"v":"由应用程序开发者控制-》由系统控制"},{"t":"list_item","d":5,"p":{},"v":"尽可能使用现有的系统调用，同时添加新的系统调用支持TCP/IP"},{"t":"list_item","d":5,"p":{},"v":"bsdnuixsocket成为事实上的标准"}]},{"t":"heading","d":3,"p":{},"v":"指明一个协议接口","c":[{"t":"list_item","d":5,"p":{},"v":"专门针对TCP/IP，还是可以为其他协议所用","c":[{"t":"list_item","d":7,"p":{},"v":"专门支持tcpip通信的一些函数"},{"t":"list_item","d":7,"p":{},"v":"支持一般网络通信的函数，用参数限定tcpip通信作为一种特例"}]},{"t":"list_item","d":5,"p":{},"v":"具有通用性，tcpip是一个族PF_INET"},{"t":"list_item","d":5,"p":{},"v":"使用服务的类型而不是指定协议名"},{"t":"list_item","d":5,"p":{},"v":"争论","c":[{"t":"list_item","d":7,"p":{},"v":"通用性没有必要，使应用程序难以阅读"},{"t":"list_item","d":7,"p":{},"v":"通用性可以使程序员免于了解协议族的细节"}]}]},{"t":"heading","d":3,"p":{},"v":"描述符","c":[{"t":"list_item","d":5,"p":{},"v":"文件描述符：进程描述符表下标。os中每个进程对应一个文件描述符表，表中每个元素指向和文件相对应的一个内部的数据结构。"},{"t":"list_item","d":5,"p":{},"v":"套接字和文件类似，每个活动套接字使用一个小整数标识，进程的文件描述符和套接字描述符值不能相同"},{"t":"list_item","d":5,"p":{},"v":"socket函数：创建套接字描述符","c":[{"t":"list_item","d":7,"p":{},"v":"使用socket将创建一个新的描述符条目"},{"t":"list_item","d":7,"p":{},"v":"针对套接字的系统数据结构的许多字段使其他的系统调用来填"}]}]},{"t":"heading","d":3,"p":{},"v":"主动套接字/被动套接字","c":[{"t":"list_item","d":5,"p":{},"v":"创建方式相同，使用方式不同"},{"t":"list_item","d":5,"p":{},"v":"等待传入连接的套接字-被动，如服务器套接字"},{"t":"list_item","d":5,"p":{},"v":"发起连接的套接字-主动，如客户套接字"},{"t":"list_item","d":5,"p":{},"v":"指明端点地址：创建时不指定，使用时指明","c":[{"t":"list_item","d":7,"p":{},"v":"tcpip需要指明协议端口号和ip地址"},{"t":"list_item","d":7,"p":{},"v":"tcp/ip协议族：PF_INET"},{"t":"list_item","d":7,"p":{},"v":"TCPIP的地址族：AF_INET"}]}]},{"t":"heading","d":3,"p":{},"v":"类属地址结构","c":[{"t":"list_item","d":5,"p":{},"v":"套接字系统定义的一般化的地址结构","c":[{"t":"list_item","d":7,"p":{},"v":"地址族，该族的端点地址"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">//套接字的普通C定义结构</span>\n<span class=\"token keyword\">struct</span> <span class=\"token class-name\">sockaddr</span> <span class=\"token punctuation\">{</span>\nu_char    sa_len<span class=\"token punctuation\">;</span>\nu_short   sa_family；\n<span class=\"token keyword\">char</span>   sa_data<span class=\"token punctuation\">[</span><span class=\"token number\">14</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><span class=\"token comment\">//14B</span>\n<span class=\"token punctuation\">}</span><span class=\"token comment\">//通用的地址结构（只是很适用于AF_INET族中的地址）</span>\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">//TCP/IP的地址定义</span>\n<span class=\"token keyword\">struct</span> <span class=\"token class-name\">sockaddr_in</span> \n<span class=\"token punctuation\">{</span> \nu_char    sin_len<span class=\"token punctuation\">;</span>\nu_short   sin_family；\nu_short    sin_port；<span class=\"token comment\">//2B</span>\n<span class=\"token keyword\">struct</span> <span class=\"token class-name\">in_addr</span>   sin_addr<span class=\"token punctuation\">;</span><span class=\"token comment\">//4B</span>\n<span class=\"token keyword\">char</span>   sin_zero<span class=\"token punctuation\">[</span><span class=\"token number\">8</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><span class=\"token comment\">//8B</span>\n<span class=\"token punctuation\">}</span> <span class=\"token comment\">//IP专用的结构</span>\n</code></pre>\n"}]}]},{"t":"heading","d":3,"p":{},"v":"套接字API的主要系统调用","c":[{"t":"list_item","d":5,"p":{},"v":"套接字调用分为两组","c":[{"t":"list_item","d":7,"p":{},"v":"主调用：提供下层功能的访问"},{"t":"list_item","d":7,"p":{},"v":"实用例程：提供帮助"}]},{"t":"list_item","d":5,"p":{},"v":"套接字带有参数，允许以多种方式来使用它们","c":[{"t":"list_item","d":7,"p":{},"v":"可被客户或服务器使用"},{"t":"list_item","d":7,"p":{},"v":"可悲TCP或UDP使用"},{"t":"list_item","d":7,"p":{},"v":"可使用特定或非特定的远程端点地址"}]}]},{"t":"heading","d":3,"p":{},"v":"在程序中使用套接字调用","c":[{"t":"list_item","d":5,"p":{},"v":"<img src=\"./tcpIp_4.png\" alt=\"cs socket\">"}]},{"t":"heading","d":3,"p":{},"v":"一些主调用的套接字API","c":[{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> <span class=\"token function\">Socket</span><span class=\"token punctuation\">(</span> <span class=\"token keyword\">int</span> domain<span class=\"token punctuation\">,</span> <span class=\"token keyword\">int</span> type<span class=\"token punctuation\">,</span> <span class=\"token keyword\">int</span> protocol<span class=\"token punctuation\">)</span>\n</code></pre>\n","c":[{"t":"list_item","d":7,"p":{},"v":"功能：创建一个新的套接字，返回套接字描述符"},{"t":"list_item","d":7,"p":{},"v":"参数：","c":[{"t":"list_item","d":9,"p":{},"v":"domain：域类型，指明调用的协议栈，如TCP/IP使用的时PF_INET"},{"t":"list_item","d":9,"p":{},"v":"type：指明需要的服务类型，如","c":[{"t":"list_item","d":11,"p":{},"v":"SOCK_DGRAM:数据报服务，udp协议"},{"t":"list_item","d":11,"p":{},"v":"SOCK_STREAM:流服务，TCP协议"}]},{"t":"list_item","d":9,"p":{},"v":"protocol：一般取0（已经指定了服务类型）"},{"t":"list_item","d":9,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">s<span class=\"token operator\">=</span><span class=\"token function\">socket</span><span class=\"token punctuation\">(</span>PF_INET<span class=\"token punctuation\">,</span>SOCK_STREAM<span class=\"token punctuation\">,</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n</code></pre>\n"}]}]},{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> <span class=\"token function\">bind</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> sockfd<span class=\"token punctuation\">,</span><span class=\"token keyword\">struct</span> <span class=\"token class-name\">sockaddr</span> <span class=\"token operator\">*</span> my_addr<span class=\"token punctuation\">,</span><span class=\"token keyword\">int</span> addrlen<span class=\"token punctuation\">)</span>\n</code></pre>\n","c":[{"t":"list_item","d":7,"p":{},"v":"功能：为套接字指明一个本地端点地址","c":[{"t":"list_item","d":9,"p":{},"v":"TCP/IP协议使用sockaddr_in结构，包含IP地址和端口号"},{"t":"list_item","d":9,"p":{},"v":"服务器使用它来指明熟知的端口号，然后等待连接"},{"t":"list_item","d":9,"p":{},"v":"参数：","c":[{"t":"list_item","d":11,"p":{},"v":"sockfd：套接字描述符，指明创建连接的套接字"},{"t":"list_item","d":11,"p":{},"v":"my_addr:本地地址，IP地址和端口号"},{"t":"list_item","d":11,"p":{},"v":"addrlen：地址长度"}]}]},{"t":"list_item","d":7,"p":{},"v":"bind(sockfd, (struct sockaddr*)&amp;address,sizeof(address));"}]},{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> <span class=\"token function\">listen</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> sockfd<span class=\"token punctuation\">,</span><span class=\"token keyword\">int</span> input_queue_size<span class=\"token punctuation\">)</span>\n</code></pre>\n","c":[{"t":"list_item","d":7,"p":{},"v":"面向连接的sock使用它将一个sock置为被动模式，并准备传入连接。用于server，指明某个sock连接时被动的"},{"t":"list_item","d":7,"p":{},"v":"参数","c":[{"t":"list_item","d":9,"p":{},"v":"sockfd：套接字描述符，指明连接的套接字"},{"t":"list_item","d":9,"p":{},"v":"input_queue_size：该sock使用的队列长度，指定在请求队列中允许的最大请求数"}]},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token function\">listen</span><span class=\"token punctuation\">(</span>sockfd<span class=\"token punctuation\">,</span><span class=\"token number\">20</span><span class=\"token punctuation\">)</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> <span class=\"token function\">accept</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> sockfd<span class=\"token punctuation\">,</span> <span class=\"token keyword\">struct</span> <span class=\"token class-name\">sockaddr</span> <span class=\"token operator\">*</span>addr<span class=\"token punctuation\">,</span> <span class=\"token keyword\">int</span> <span class=\"token operator\">*</span>addrlen<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> \n</code></pre>\n","c":[{"t":"list_item","d":7,"p":{},"v":"功能：获取传入连接请求，返回新的连接的套接字描述符","c":[{"t":"list_item","d":9,"p":{},"v":"为每个新连接请求创建了新sock，服务器支队新连接使用该sock，原理的监听sock接受其他连接请求"},{"t":"list_item","d":9,"p":{},"v":"新的连接上传输数据使用新的套接字，使用完毕，服务器将关闭这个套接字。"}]},{"t":"list_item","d":7,"p":{},"v":"参数：","c":[{"t":"list_item","d":9,"p":{},"v":"addr：提出连接请求地址"},{"t":"list_item","d":9,"p":{},"v":"addrlen:地址长度"}]},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">new_sockfd <span class=\"token operator\">=</span> <span class=\"token function\">accept</span><span class=\"token punctuation\">(</span>sockfd<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">struct</span> <span class=\"token class-name\">sockaddr</span> <span class=\"token operator\">*</span><span class=\"token punctuation\">)</span><span class=\"token operator\">&amp;</span>address<span class=\"token punctuation\">,</span> <span class=\"token keyword\">sizeof</span><span class=\"token punctuation\">(</span>address<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> \n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> connect（<span class=\"token keyword\">int</span> sockfd<span class=\"token punctuation\">,</span><span class=\"token keyword\">struct</span> <span class=\"token class-name\">sockaddr</span> <span class=\"token operator\">*</span>server_addr<span class=\"token punctuation\">,</span><span class=\"token keyword\">int</span> sockaddr_len）\n</code></pre>\n","c":[{"t":"list_item","d":7,"p":{},"v":"功能：同远程服务器建立主动连接，成功时返回0，若连接失败返回-1"},{"t":"list_item","d":7,"p":{},"v":"参数说明：","c":[{"t":"list_item","d":9,"p":{},"v":"server_addr:指明远程端点：ip地址和端口号"},{"t":"list_item","d":9,"p":{},"v":"sockaddr_len：地址长度"}]},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token function\">connect</span><span class=\"token punctuation\">(</span>s<span class=\"token punctuation\">,</span>remaddr<span class=\"token punctuation\">,</span>remaddrlen<span class=\"token punctuation\">)</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> <span class=\"token function\">send</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> sockfd<span class=\"token punctuation\">,</span> <span class=\"token keyword\">const</span> <span class=\"token keyword\">void</span> <span class=\"token operator\">*</span> data<span class=\"token punctuation\">,</span> <span class=\"token keyword\">int</span> data_len<span class=\"token punctuation\">,</span> <span class=\"token keyword\">unsigned</span> <span class=\"token keyword\">int</span> flags<span class=\"token punctuation\">)</span>\n</code></pre>\n","c":[{"t":"list_item","d":7,"p":{},"v":"功能：","c":[{"t":"list_item","d":9,"p":{},"v":"在tcp连接上发送数据，返回成功传输数据的长度，出错时返回-1"},{"t":"list_item","d":9,"p":{},"v":"send会将外发数据复制到OS内核中，也可以使用send发送面向连接的udp报文"}]},{"t":"list_item","d":7,"p":{},"v":"参数说明：","c":[{"t":"list_item","d":9,"p":{},"v":"sockfd：套接字描述符"},{"t":"list_item","d":9,"p":{},"v":"data：指向要发送数据的指针"},{"t":"list_item","d":9,"p":{},"v":"data——len：数据长度"},{"t":"list_item","d":9,"p":{},"v":"flags：通常为0"}]},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token function\">send</span><span class=\"token punctuation\">(</span>s<span class=\"token punctuation\">,</span>req<span class=\"token punctuation\">,</span><span class=\"token function\">strlen</span><span class=\"token punctuation\">(</span>req<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> <span class=\"token function\">sendto</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> sockfd<span class=\"token punctuation\">,</span> <span class=\"token keyword\">const</span> <span class=\"token keyword\">void</span> <span class=\"token operator\">*</span> data<span class=\"token punctuation\">,</span> <span class=\"token keyword\">int</span> data_len<span class=\"token punctuation\">,</span> <span class=\"token keyword\">unsigned</span> <span class=\"token keyword\">int</span> flags<span class=\"token punctuation\">,</span> <span class=\"token keyword\">struct</span> <span class=\"token class-name\">sockaddr</span> <span class=\"token operator\">*</span>remaddr<span class=\"token punctuation\">,</span><span class=\"token keyword\">int</span> remaddr_len）<span class=\"token comment\">//udp发送，返回实际发送数据长度出错返回-1</span>\n</code></pre>\n"},{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> <span class=\"token function\">recv</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> sockfd<span class=\"token punctuation\">,</span> <span class=\"token keyword\">void</span> <span class=\"token operator\">*</span>buf<span class=\"token punctuation\">,</span> <span class=\"token keyword\">int</span> buf_len<span class=\"token punctuation\">,</span><span class=\"token keyword\">unsigned</span> <span class=\"token keyword\">int</span> flags<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">//TCP接受，返回实际接受的数据长度，出错返回-1</span>\n</code></pre>\n","c":[{"t":"list_item","d":7,"p":{},"v":"<strong>服务器使用其接收客户请求，客户使用它接受服务器的应答。如果没有数据，将阻塞</strong>"},{"t":"list_item","d":7,"p":{},"v":"**如果TCP **收到的数据大于（小于)缓存的大小，只抽出能够填满缓存的足够数据(/抽出所有数据并返回它实际接收的字节数)。"},{"t":"list_item","d":7,"p":{},"v":"也可以使用recv接收面向连接的UDP的报文，若缓存不能装下整个报文，填满缓存后剩下的数据将被丢弃。"}]},{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> <span class=\"token function\">recvfrom</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> sockfd<span class=\"token punctuation\">,</span> <span class=\"token keyword\">void</span> <span class=\"token operator\">*</span>buf<span class=\"token punctuation\">,</span> <span class=\"token keyword\">int</span> buf_len<span class=\"token punctuation\">,</span><span class=\"token keyword\">unsigned</span> <span class=\"token keyword\">int</span> flags<span class=\"token punctuation\">,</span><span class=\"token keyword\">struct</span> <span class=\"token class-name\">sockaddr</span> <span class=\"token operator\">*</span>from<span class=\"token punctuation\">,</span><span class=\"token keyword\">int</span> fromlen<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">//UDP接受，返回实际接受的字节数，失败时返回-1</span>\n</code></pre>\n"},{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token function\">close</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> sockfd<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><span class=\"token comment\">//撤销套接字</span>\n</code></pre>\n","c":[{"t":"list_item","d":7,"p":{},"v":"<strong>如果****只有****一个进程使用，立即终止连接并撤销该套接字，如果多个进程共享该套接字，将引用数减一，如果引用数降到零，则撤销它</strong>"}]}]},{"t":"heading","d":3,"p":{},"v":"套接字调用参数使用的符号常量","c":[{"t":"list_item","d":5,"p":{},"v":"unix系统提供了预定义的符号常量和数据结构来声明数据和指明参数"},{"t":"list_item","d":5,"p":{},"v":"使用","c":[{"t":"list_item","d":7,"p":{},"v":"SOCK_DGRAM:数据报服务，udp协议"},{"t":"list_item","d":7,"p":{},"v":"SOCK_STREAM:流服务，tcp协议"},{"t":"list_item","d":7,"p":{},"v":"PF_INET：使用tcpip协议族"},{"t":"list_item","d":7,"p":{},"v":"AF_INET:使用tcpip地址结构"}]},{"t":"list_item","d":5,"p":{},"v":"需要include，引用出现这些定义的文本","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">include</span> <span class=\"token string\">&lt;sys/types.h></span></span>\n<span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">include</span> <span class=\"token string\">&lt;sys/socket.h></span></span>\n</code></pre>\n"}]}]}]},{"t":"heading","d":2,"p":{},"v":"客户软件设计中的算法和问题","c":[{"t":"heading","d":3,"p":{},"v":"应用程序定义细节","c":[{"t":"list_item","d":5,"p":{},"v":"c/s"},{"t":"list_item","d":5,"p":{},"v":"端点地址"},{"t":"list_item","d":5,"p":{},"v":"连接/无连接"},{"t":"list_item","d":5,"p":{},"v":"授权与防护准则"},{"t":"list_item","d":5,"p":{},"v":"缓存大小"},{"t":"list_item","d":5,"p":{},"v":"需要详细了解构造通信程序的各种方法，便于迅速作出设计决策"}]},{"t":"heading","d":3,"p":{},"v":"客户体系结构","c":[{"t":"list_item","d":5,"p":{},"v":"不必明显的处理并发性"},{"t":"list_item","d":5,"p":{},"v":"不需要特权，和常规apg一样执行"},{"t":"list_item","d":5,"p":{},"v":"不需要强行保护，依赖操作系统自动强迫执行保护"}]},{"t":"heading","d":3,"p":{},"v":"标识服务器的位置","c":[{"t":"list_item","d":5,"p":{},"v":"编译程序时，将服务器的域名或IP说明为常量","c":[{"t":"list_item","d":7,"p":{},"v":"执行快，但服务器移动将不方便"}]},{"t":"list_item","d":5,"p":{},"v":"要求用户在启动程序时标定服务器","c":[{"t":"list_item","d":7,"p":{},"v":"使用机器名，不必重新编译客户程序"}]},{"t":"list_item","d":5,"p":{},"v":"从稳定的存储设备中获得关于服务器的信息","c":[{"t":"list_item","d":7,"p":{},"v":"如果文件不存在，客户软件就不能执行"}]},{"t":"list_item","d":5,"p":{},"v":"使用某个单独的协议来找到服务器（广播/组播）","c":[{"t":"list_item","d":7,"p":{},"v":"只能在本地小环境下应用"}]},{"t":"list_item","d":5,"p":{},"v":"实际：用户在调用客户软件时指明服务器地址，根据实际情况，综合表示服务器地址"}]},{"t":"heading","d":3,"p":{},"v":"分析地址参数","c":[{"t":"list_item","d":5,"p":{},"v":"客户程序调用时指明参数：域名方式/ip地址方式"},{"t":"list_item","d":5,"p":{},"v":"域名和ip地址的确定：扫描参数，观察是否含有字母"},{"t":"list_item","d":5,"p":{},"v":"全参数化的客户软件允许用户指明协议端口号和机器","c":[{"t":"list_item","d":7,"p":{},"v":"两个参数：www.163.com smtp"},{"t":"list_item","d":7,"p":{},"v":"一个参数：www.163.com:smtp"}]},{"t":"list_item","d":5,"p":{},"v":"遵循本地系统的约定：linux使用单独参数指明报务器的机器地址和协议端口"}]},{"t":"heading","d":3,"p":{},"v":"查找域名","c":[{"t":"list_item","d":5,"p":{},"v":"使用sockaddr_in结构指明服务器的地址","c":[{"t":"list_item","d":7,"p":{},"v":"需要二进制表示的32bitIP地址"}]},{"t":"list_item","d":5,"p":{},"v":"套接字对地址转换的支持","c":[{"t":"list_item","d":7,"p":{},"v":"inet_addr:IP地址点分十进制的字符串到二进制的转换","c":[{"t":"list_item","d":9,"p":{},"v":"接受一个点分十进制表示的字符串地址，返回一个等价的二进制地址"}]},{"t":"list_item","d":7,"p":{},"v":"gethostbyname:主机域名到二进制的转换","c":[{"t":"list_item","d":9,"p":{},"v":"接受一个机器域名字符串，返回一个hostent结构，内含一个二进制表示的主机IP地址"}]}]},{"t":"list_item","d":5,"p":{},"v":"IP地址点分十进制字符串转换到二进制","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">//TCP/IP的地址定义</span>\n<span class=\"token keyword\">struct</span> <span class=\"token class-name\">sockaddr_in</span> \n<span class=\"token punctuation\">{</span> \nu_char    sin_len<span class=\"token punctuation\">;</span>\nu_short   sin_family；\nu_short    sin_port；<span class=\"token comment\">//2B</span>\n<span class=\"token keyword\">struct</span> <span class=\"token class-name\">in_addr</span>   sin_addr<span class=\"token punctuation\">;</span><span class=\"token comment\">//4B</span>\n<span class=\"token keyword\">char</span>   sin_zero<span class=\"token punctuation\">[</span><span class=\"token number\">8</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span><span class=\"token comment\">//8B</span>\n<span class=\"token punctuation\">}</span> <span class=\"token comment\">//IP专用的结构</span>\n<span class=\"token keyword\">struct</span> <span class=\"token class-name\">sockaddr_in</span> sock<span class=\"token punctuation\">;</span>\nsock<span class=\"token punctuation\">.</span>sin_addr<span class=\"token punctuation\">.</span>s_addr<span class=\"token operator\">=</span><span class=\"token function\">inet_addr</span><span class=\"token punctuation\">(</span>“<span class=\"token number\">192.168</span><span class=\"token number\">.0</span><span class=\"token number\">.1</span>”<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">//接受一个点分十进制表示的字符串的地址，返回一个等价二进制地址</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"查找域名","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">//客户使用gethostbyname</span>\n<span class=\"token keyword\">struct</span> <span class=\"token class-name\">hostent</span>  <span class=\"token operator\">*</span>hptr<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">char</span>    <span class=\"token operator\">*</span>exname<span class=\"token operator\">=</span>“mail<span class=\"token punctuation\">.</span>sina<span class=\"token punctuation\">.</span>com<span class=\"token punctuation\">.</span>cn<span class=\"token punctuation\">;</span>\n\n<span class=\"token function\">If</span><span class=\"token punctuation\">(</span>hptr <span class=\"token operator\">=</span> <span class=\"token function\">gethostbyname</span><span class=\"token punctuation\">(</span>exname<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">/*IP address is now in \n        hptr ->h_addr */</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token keyword\">else</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">/* error in name-handle it */</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">//hostent在文件netdb.h的定义</span>\n<span class=\"token keyword\">struct</span> <span class=\"token class-name\">hostent</span> <span class=\"token punctuation\">{</span>\n<span class=\"token keyword\">char</span>    <span class=\"token operator\">*</span>h_name<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">char</span>       <span class=\"token operator\">*</span><span class=\"token operator\">*</span>h_aliases<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">int</span>     h_addrtype<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">int</span>     h_length<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">char</span>    <span class=\"token operator\">*</span><span class=\"token operator\">*</span>h_addr_list<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n<span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">define</span> <span class=\"token expression\">h_addr   h_addr_list<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span></span></span>\n<span class=\"token comment\">//h_addr指向主机地址表第一个位置</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"由名字查找某个熟知端口","c":[{"t":"list_item","d":7,"p":{},"v":"getservbyname：两个参数指明期望的服务和协议。返回servent类型的结构指针"},{"t":"list_item","d":7,"p":{},"v":"注意网络字节顺序和本地机器的表示方法"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">struct</span> <span class=\"token class-name\">servent</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">char</span>  <span class=\"token operator\">*</span>s_name<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">char</span>  <span class=\"token operator\">*</span><span class=\"token operator\">*</span>s_aliases<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">int</span>     s_port<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">char</span>  <span class=\"token operator\">*</span>s_proto<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">struct</span> <span class=\"token class-name\">servent</span> <span class=\"token operator\">*</span>sptr<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>sptr <span class=\"token operator\">=</span> <span class=\"token function\">getservbyname</span><span class=\"token punctuation\">(</span>“smtp”<span class=\"token punctuation\">,</span> “tcp”<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n     <span class=\"token comment\">/* port number is now in sptr ->s_port*/</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token keyword\">else</span>\n<span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/* error occurred-handle it */</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"由名字查找协议","c":[{"t":"list_item","d":7,"p":{},"v":"getprotobyname:由协议名返回协议号；返回一个protoent类型结构的地址"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">struct</span>  <span class=\"token class-name\">protoent</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">char</span>  <span class=\"token operator\">*</span>p_name<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">char</span>  <span class=\"token operator\">*</span><span class=\"token operator\">*</span>p_aliases<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">int</span>  p_proto<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">struct</span> <span class=\"token class-name\">protoent</span> <span class=\"token operator\">*</span>pptr<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>pptr <span class=\"token operator\">=</span> <span class=\"token function\">getprotobyname</span><span class=\"token punctuation\">(</span>“udp”<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n       <span class=\"token comment\">/* official protocol number is now in pptr ->p_proto*/</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token keyword\">else</span>\n<span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">/* error occurred-handle it */</span>\n<span class=\"token punctuation\">}</span>\n\n</code></pre>\n"}]}]},{"t":"heading","d":3,"p":{},"v":"TCP客户算法","c":[{"t":"list_item","d":5,"p":{},"v":"面向连接的客户","c":[{"t":"list_item","d":7,"p":{},"v":"找到期望与之通信的服务器ip地址和协议端口号"},{"t":"list_item","d":7,"p":{},"v":"分配套接字","c":[{"t":"list_item","d":9,"p":{},"v":"使用socket函数"},{"t":"list_item","d":9,"p":{},"v":"将协议和服务分别说明为PF_INET和SOCK_STREAM"},{"t":"list_item","d":9,"p":{},"v":"include语句包含一些定义常量的文件"},{"t":"list_item","d":9,"p":{},"v":"对于tcpip，第三个参数无用","c":[{"t":"list_item","d":11,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">include</span> <span class=\"token string\">&lt;sys/types.h></span></span>\n<span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">include</span> <span class=\"token string\">&lt;sys/socket.h></span></span>\n<span class=\"token keyword\">int</span>     s<span class=\"token punctuation\">;</span>    <span class=\"token comment\">/* socket descriptor */</span>\ns <span class=\"token operator\">=</span> <span class=\"token function\">socket</span> <span class=\"token punctuation\">(</span> PF_INET<span class=\"token punctuation\">,</span> SOCK_STREAM<span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</code></pre>\n"}]}]},{"t":"list_item","d":7,"p":{},"v":"指明此连接需要在本地机器中、任意的、未使用的协议端口号，并允许tcp选择一个这样的端口","c":[{"t":"list_item","d":9,"p":{},"v":"服务器运行于熟知端口，客户非"},{"t":"list_item","d":9,"p":{},"v":"客户端口规则","c":[{"t":"list_item","d":11,"p":{},"v":"不与该机器其他进程使用端口冲突"},{"t":"list_item","d":11,"p":{},"v":"没有被分配给某个熟知服务"}]},{"t":"list_item","d":9,"p":{},"v":"客户允许tcp自动选择本地端口","c":[{"t":"list_item","d":11,"p":{},"v":"connect调用能满足上述准则"}]}]},{"t":"list_item","d":7,"p":{},"v":"将这个套接字连接到服务器","c":[{"t":"list_item","d":9,"p":{},"v":"connect：允许tcp套接字发起连接","c":[{"t":"list_item","d":11,"p":{},"v":"强迫执行下层三次握手"},{"t":"list_item","d":11,"p":{},"v":"超时/建立连接后返回"},{"t":"list_item","d":11,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">//三个参数</span>\nretcode <span class=\"token operator\">=</span> <span class=\"token function\">connect</span><span class=\"token punctuation\">(</span>s<span class=\"token punctuation\">,</span> remaddr<span class=\"token punctuation\">,</span> remaddrlen<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">//s: 套接字的描述符</span>\n<span class=\"token comment\">//remaddr:一个sockaddr_in类型结构的地址</span>\n<span class=\"token comment\">//remaddrlen:第二个参数的长度</span>\n</code></pre>\n"}]},{"t":"list_item","d":9,"p":{},"v":"connect四项任务","c":[{"t":"list_item","d":11,"p":{},"v":"对指明的套接字进行检测：有效，还没有连接"},{"t":"list_item","d":11,"p":{},"v":"将第二个参数给出的端点地址填入套接字中"},{"t":"list_item","d":11,"p":{},"v":"为此套接字选择一个本地端点地址"},{"t":"list_item","d":11,"p":{},"v":"发起一个tcp连接，并返回一个值"}]}]},{"t":"list_item","d":7,"p":{},"v":"使用应用级协议与服务器通信"},{"t":"list_item","d":7,"p":{},"v":"关闭连接"}]},{"t":"list_item","d":5,"p":{},"v":"一般本地地址字段不填，允许TCP/IP自动选取本地ip地址"},{"t":"list_item","d":5,"p":{},"v":"使用tcp和服务器通信","c":[{"t":"list_item","d":7,"p":{},"v":"客户发送请求，等待响应"},{"t":"list_item","d":7,"p":{},"v":"发送请求：send"},{"t":"list_item","d":7,"p":{},"v":"等待响应：recv","c":[{"t":"list_item","d":9,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token function\">send</span><span class=\"token punctuation\">(</span>s<span class=\"token punctuation\">,</span> req<span class=\"token punctuation\">,</span> <span class=\"token function\">strlen</span><span class=\"token punctuation\">(</span>req<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">while</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>n <span class=\"token operator\">=</span> <span class=\"token function\">recv</span> <span class=\"token punctuation\">(</span>s<span class=\"token punctuation\">,</span> bptr<span class=\"token punctuation\">,</span> buflen<span class=\"token punctuation\">,</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">></span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\nbptr <span class=\"token operator\">+=</span>n<span class=\"token punctuation\">;</span>\nbuflen <span class=\"token operator\">-=</span>n；\n<span class=\"token punctuation\">}</span>\n</code></pre>\n"}]},{"t":"list_item","d":7,"p":{},"v":"tcp不保持记录的边界，面向流的概念，多次接收。","c":[{"t":"list_item","d":9,"p":{},"v":"大块数据被分片封装发送"},{"t":"list_item","d":9,"p":{},"v":"接受方接受缓冲小而数据被发送方分次发送"}]}]},{"t":"list_item","d":5,"p":{},"v":"关闭Tcp连接","c":[{"t":"list_item","d":7,"p":{},"v":"close：从容关闭连接释放该套接字","c":[{"t":"list_item","d":9,"p":{},"v":"常常需要在客户服务器之间协调关闭事宜","c":[{"t":"list_item","d":11,"p":{},"v":"服务器不能关闭连接，不知客户请求是否完成"},{"t":"list_item","d":11,"p":{},"v":"客户不知道服务器发出的数据是否全部到达"}]}]},{"t":"list_item","d":7,"p":{},"v":"允许应用程序在一个方向关闭tcp连接","c":[{"t":"list_item","d":9,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token function\">shutdown</span><span class=\"token punctuation\">(</span>s<span class=\"token punctuation\">,</span>direction<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">//direction:0不允许输入;1不允许输出；2双向关闭</span>\n</code></pre>\n"}]}]}]},{"t":"heading","d":3,"p":{},"v":"udp客户的编程","c":[{"t":"list_item","d":5,"p":{},"v":"找到期望与之通信的服务器ip和协议端口号"},{"t":"list_item","d":5,"p":{},"v":"分配套接字"},{"t":"list_item","d":5,"p":{},"v":"指明这种通信需要本地机器中的、任意的、未使用的协议端口，并允许udp选择一个这样的端口"},{"t":"list_item","d":5,"p":{},"v":"指明报文所要发往的服务器"},{"t":"list_item","d":5,"p":{},"v":"使用应用级协议于服务器通信"},{"t":"list_item","d":5,"p":{},"v":"关闭连接","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">/*\nclose: 关闭套接字，释放与之关联的资源\n拒绝以后到达的报文\n没有通知远程端点\nshutdown: 在某个方向上终止进一步传输\n不向另外一方发送任何通知报文，只是在本地套接字标明不期望在指定的方向传输数据\n客户关闭输出以后，服务器并不知道\nUDP提供的是不可靠的交互\n必须自己设计协议实现可靠性\n*/</span>\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":""}]},{"t":"list_item","d":5,"p":{},"v":"连接的udp","c":[{"t":"list_item","d":7,"p":{},"v":"使用connect调用指明远程端点地址","c":[{"t":"list_item","d":9,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">/*\n使用SOCK_DGRAM类型的套接字\n不发起任何分组交换，不检查远程端点合法性\n只是在套接字的数据结构记录远程端点的信息\n*/</span>\n<span class=\"token comment\">/*\n使用send发送报文\n使用recv接收报文\n每次send发送一个完整的报文\n每次recv接受一个完整的报文，足够大缓存\n不需要重复使用recv获得单个报文\n*/</span>\n</code></pre>\n"}]},{"t":"list_item","d":7,"p":{},"v":"不用重复指明远端地址收发报文"},{"t":"list_item","d":7,"p":{},"v":"只和一个服务器交互比较方便"}]},{"t":"list_item","d":5,"p":{},"v":"非链接udp","c":[{"t":"list_item","d":7,"p":{},"v":"每次发送报文时指明远端地址"},{"t":"list_item","d":7,"p":{},"v":"使用灵活，便于不同的服务器通信"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">/*\nsendto: 发送报文，含有地址信息 \nrecvfrom:接收一个含有源地址的数据报\n*/</span>\n</code></pre>\n"}]}]}]},{"t":"heading","d":2,"p":{},"v":"客户程序举例","c":[{"t":"heading","d":3,"p":{},"v":"特点","c":[{"t":"list_item","d":5,"p":{},"v":"服务本身代码少，容易理解"},{"t":"list_item","d":5,"p":{},"v":"突出基本算法"},{"t":"list_item","d":5,"p":{},"v":"说明客户/服务器如何使用系统调用"},{"t":"list_item","d":5,"p":{},"v":"说明代码长短和服务数量的关系"},{"t":"list_item","d":5,"p":{},"v":"模块化，过程化：隐藏细节：将复杂的程序分解成一组过程，模块化的程序","c":[{"t":"list_item","d":7,"p":{},"v":"网络软件含有很多细节，隐藏细节减少出错机会"},{"t":"list_item","d":7,"p":{},"v":"重用代码"},{"t":"list_item","d":7,"p":{},"v":"将依赖操作系统的代码隔离出来，<strong>便于移植</strong>"}]}]},{"t":"heading","d":3,"p":{},"v":"针对客户程序的过程库例子","c":[{"t":"list_item","d":5,"p":{},"v":"每个客户与服务器建立联系","c":[{"t":"list_item","d":7,"p":{},"v":"选择协议（UDP/TCP）"},{"t":"list_item","d":7,"p":{},"v":"查找服务器的机器名"},{"t":"list_item","d":7,"p":{},"v":"查找所期望的服务并将器映射到协议端口号"},{"t":"list_item","d":7,"p":{},"v":"分配套接字并阈值连接"}]},{"t":"list_item","d":5,"p":{},"v":"将这部分工作进行封装，置于某个过程当中，只需一次编码","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">socket <span class=\"token operator\">=</span> <span class=\"token function\">connectTCP</span><span class=\"token punctuation\">(</span>machine<span class=\"token punctuation\">,</span> service<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\nsocket <span class=\"token operator\">=</span> <span class=\"token function\">connectUDP</span><span class=\"token punctuation\">(</span>machine<span class=\"token punctuation\">,</span> service<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"正确抽象：高级操作，共享代码，减少出错"},{"t":"list_item","d":5,"p":{},"v":"实现connectTCP/connectUDP","c":[{"t":"list_item","d":7,"p":{},"v":"将所有的底层操作放置到connectsock中"},{"t":"list_item","d":7,"p":{},"v":"实现connectTCP和CONNECTUDP成为简单调用"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> <span class=\"token function\">connectTCP</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">const</span> <span class=\"token keyword\">char</span> <span class=\"token operator\">*</span>host<span class=\"token punctuation\">,</span> <span class=\"token keyword\">const</span> <span class=\"token keyword\">char</span> <span class=\"token operator\">*</span>service<span class=\"token punctuation\">)</span>\n<span class=\"token comment\">/*  Arguments\n    host    -name of host to which connection is desired\n    service –service associated with the desired port\n*/</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token function\">connectsock</span><span class=\"token punctuation\">(</span>host<span class=\"token punctuation\">,</span> service<span class=\"token punctuation\">,</span> “tcp”<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> <span class=\"token function\">connectUDP</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">const</span> <span class=\"token keyword\">char</span> <span class=\"token operator\">*</span>host<span class=\"token punctuation\">,</span> <span class=\"token keyword\">const</span> <span class=\"token keyword\">char</span> <span class=\"token operator\">*</span>service<span class=\"token punctuation\">)</span>\n<span class=\"token comment\">/*  Arguments\n    host    -name of host to which connection is desired\n    service –service associated with the desired port\n*/</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token function\">connectsock</span><span class=\"token punctuation\">(</span>host<span class=\"token punctuation\">,</span> service<span class=\"token punctuation\">,</span> “udp”<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"构成连接的过程","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span>  <span class=\"token function\">connectsock</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">const</span> <span class=\"token keyword\">char</span> <span class=\"token operator\">*</span>host<span class=\"token punctuation\">,</span> <span class=\"token keyword\">const</span> <span class=\"token keyword\">char</span> <span class=\"token operator\">*</span>service<span class=\"token punctuation\">,</span>     <span class=\"token keyword\">const</span> <span class=\"token keyword\">char</span> <span class=\"token operator\">*</span>transport<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">/*\nconnectsock：含有所有需要用来分配套接字和连接该套接字的代码，p58\n#include 语句\n宏定义和变量定义，函数声明，功能说明\n函数名称和参数说明\n局部变量定义\n取得端口号，IP地址，和使用协议号\n使用socket得到套接字\n使用connect建立连接\n返回套接字\n*/</span>\n<span class=\"token comment\">/*\n复杂条件表达式:函数调用，赋值，比较在一行\nmemset和memcpy的使用特点\n辅助的系统调用：gethostbyname, getprotobyname, getservbyname.\nerrexit: 出错退出\n*/</span>\n</code></pre>\n"}]}]},{"t":"heading","d":3,"p":{},"v":"DAYTIME服务","c":[{"t":"list_item","d":5,"p":{},"v":"允许用户获得当前的日期和时间"},{"t":"list_item","d":5,"p":{},"v":"客户重新访问服务器获得信息"},{"t":"list_item","d":5,"p":{},"v":"tcp/udp实现，协议端口13","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">/*\n对于TCP版本\n  只要连接到来，服务器就构造包含当前日期时间的文本字符串发送，然后关闭连接。客户不用发送任何数据，发送了也会忽略。\n  */</span>\n<span class=\"token comment\">/*\nTCPdaytime.c 的实现说明。P61\n #include语句\n 变量、恒量和函数定义\n 客户程序主函数main,含参数\nint main(int argc, char *argv[])\n对参数的个数进行判断，根据参数数量的不同进行不同的参数处理\n如果出错，提示使用方法，退出\n调用TCPdaytime( )获得服务器服务\n使用connectTCP得到套接字\n循环等待服务器的响应，并送到标准文件显示\n*/</span>\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">/*\n对于UDP版本\n  服务器收到数据报，格式化当前的日期和时间将结果字符串放置到外发数据报中，发送给客户。激活这个响应的数据报会被丢失。\n*/</span>\n<span class=\"token comment\">/*\nUDPtime.c 程序说明:p65\n变量定义\n程序参数处理\n建立UDP套接字\n发送一个数据报\n读取数据报\n字节顺序转换，\n换算成unix的时间起点\n调用ctime转换成为可以读出的时间格式\n*/</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"从tcp连接中进行读","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">/*\nTCP提供流式服务，不保持记录边界\n发送应用程序和接收应用程序分开了\n发送2个64字节，可能接收1次或者3次完成\n一次TCP连接的读操作调用返回的字节数依赖于下层互联网络数据报的大小，可用的缓存空间等\n必须要重复地调用recv(或者read)，直到获得所有的数据\nTCP的流服务不能保证按写入时相同的数据块交付数据，接收方不能指望一次接收完所有数据。\n*/</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"time服务","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">允许一台机器从另外一台机器获得日期和时间。\n由于存在不同的时区，所有的时间日期信息必须用国际标准时间：UCT或UT\n服务器应答前将本地时间转化为标准时间\n客户收到应答时，将国际标准时间转化为本地时间。\nTIME协议规定由<span class=\"token number\">32</span>bit的整数来表示\n从<span class=\"token number\">1900</span>年<span class=\"token number\">1</span>月<span class=\"token number\">1</span>日午夜为起点的秒数\n用于一台计算机使用另外一系统时钟来设置日期时间\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"访问time服务","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">/*\nTIME服务使用端口37\n可以使用TCP协议\n使用TCP的TIME服务器利用连接的出现激活输出，类似DAYTIME服务。\n使用TCP的客户不用发送任何数据\n也可以使用UDP访问TIME服务\n客户发出包含单个数据报的请求\n服务器从传入的数据报中取出地址和端口号\n服务器将当前时间编码为一个整数，使用上述地址和端口号发回给客户\n*/</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"精确时间和网络延迟","c":[{"t":"list_item","d":7,"p":{},"v":"通过预加上测量延迟时间的一半进行发送，增加精度"}]}]},{"t":"heading","d":3,"p":{},"v":"ECHO服务","c":[{"t":"list_item","d":5,"p":{},"v":"返回从客户收到的所有数据"},{"t":"list_item","d":5,"p":{},"v":"用户网络管理员测试可达性，调试协议软件，识别选路问题等"},{"t":"list_item","d":5,"p":{},"v":"tcp实现","c":[{"t":"list_item","d":7,"p":{},"v":"接收连接请求，从连接中读取数据，在该连接上将数据写回。直到客户终止传送。"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">/*\nTCPecho.c p66\n客户主函数：main( ) 处理传入参数\nTCPecho( )\n打开连接以后，进入循环\n读出每行输入\n通过TCP连接发送给ECHO服务器\n读取返回的数据并打印\n读出过程是一个循环，按照字符数量计数\n完成所有的行输入后，程序退出\n*/</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"udp实现","c":[{"t":"list_item","d":7,"p":{},"v":"接收整个数据报，根据数据报指明的端口号和地址，返回整个数据报"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">/*\nUDPecho.c p67\n同前面的TCP版本类似\n读出返回数据的过程不同，只需要读出一次\nUDP客户要么收到了由服务器返回的整个行，要么什么都没有收到。\n除非出现差错，否则每次调用read都返回整个行\n*/</span>\n</code></pre>\n"}]}]}]},{"t":"heading","d":2,"p":{},"v":"服务器软件设计的算法问题","c":[{"t":"bullet_list","d":3,"p":{},"v":"","c":[{"t":"list_item","d":4,"p":{},"v":"简单服务器算法","c":[{"t":"list_item","d":6,"p":{},"v":"创建套接字"},{"t":"list_item","d":6,"p":{},"v":"绑定到一个熟知端口"},{"t":"list_item","d":6,"p":{},"v":"期望在这个端口上接收请求"},{"t":"list_item","d":6,"p":{},"v":"进入无限循环，接受客户请求并应答"},{"t":"list_item","d":6,"p":{},"v":"只适用于最简单的服务"}]},{"t":"list_item","d":4,"p":{},"v":"循环服务器：一个时刻只处理一个请求"},{"t":"list_item","d":4,"p":{},"v":"并发服务器：一个时刻可以处理多请求","c":[{"t":"list_item","d":6,"p":{},"v":"多数只提供表面并发：执行多个线程，每个线程处理一个请求"},{"t":"list_item","d":6,"p":{},"v":"使用单线程的可能性：计算量小，主要是异步I/O，便于同时使用多个通信信道"},{"t":"list_item","d":6,"p":{},"v":"并发处理多个请求，而不是指下层是否使用了多个并发线程"}]},{"t":"list_item","d":4,"p":{},"v":"循环服务器容易构建，但是性能差；并发服务器难以构建和设计，但是性能好"}]},{"t":"heading","d":3,"p":{},"v":"连接/无连接的访问","c":[{"t":"list_item","d":5,"p":{},"v":"连接性问题是传输协议的中心，TCP/IP提供了两种协议：TCP,UDP","c":[{"t":"list_item","d":7,"p":{},"v":"使用TCP的服务器是面向连接的服务器"},{"t":"list_item","d":7,"p":{},"v":"使用UDP的服务器是无连接的服务器"}]},{"t":"list_item","d":5,"p":{},"v":"选择面向连接或者无连接的服务，依赖于应用协议","c":[{"t":"list_item","d":7,"p":{},"v":"设计上使用面向连接的传输服务的应用协议，如果实际中使用了无连接的传输协议时，将可能不能正确地运行或者不能有效运行"}]}]},{"t":"heading","d":3,"p":{},"v":"传输协议的语义","c":[{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">/*\nTCP的语义\n点到点通信\n建立可靠连接\n可靠交付\n具有流控的传输\n双工传输\n流模式\n*/</span>\n</code></pre>\n"},{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">/*\nUDP的语义\n多对多通信\n不可靠服务\n缺乏流控制\n报文模式\n*/</span>\n</code></pre>\n"},{"t":"list_item","d":5,"p":{},"v":"选择传输协议，需要考虑应用程序要求的语义"}]},{"t":"heading","d":3,"p":{},"v":"面向连接的服务器","c":[{"t":"list_item","d":5,"p":{},"v":"优点","c":[{"t":"list_item","d":7,"p":{},"v":"易于编程","c":[{"t":"list_item","d":9,"p":{},"v":"自动处理分组丢失、分组失序"},{"t":"list_item","d":9,"p":{},"v":"自动验证数据差错，处理连接状态"}]}]},{"t":"list_item","d":5,"p":{},"v":"面向连接的服务的缺点","c":[{"t":"list_item","d":7,"p":{},"v":"对每个连接都有一个单独的套接字，耗费更多的资源"},{"t":"list_item","d":7,"p":{},"v":"在空闲的连接上不发送任何分组"},{"t":"list_item","d":7,"p":{},"v":"始终运行的服务器会因为客户的崩溃，导致无用套接字的过多而耗尽资源，终止运行"}]}]},{"t":"heading","d":3,"p":{},"v":"无连接的服务器","c":[{"t":"list_item","d":5,"p":{},"v":"优点：无资源耗尽问题"},{"t":"list_item","d":5,"p":{},"v":"缺陷：需要自己完成可靠通信问题","c":[{"t":"list_item","d":7,"p":{},"v":"必要时，需要一种自适应重传的复杂技术，需要程序员具有相当的专业知识"},{"t":"list_item","d":7,"p":{},"v":"对于可靠通信的场合，尽量使用tcp"}]},{"t":"list_item","d":5,"p":{},"v":"是否需要组播/广播是考虑选择何种传输方式的一个因素","c":[{"t":"list_item","d":7,"p":{},"v":"支持组播/广播的服务器必须是无连接的，今后会不断增加这样的应用"}]}]},{"t":"heading","d":3,"p":{},"v":"故障、可靠性、无状态","c":[{"t":"list_item","d":5,"p":{},"v":"状态信息：服务器维护的，关于它和客户正在进行交互状态信息","c":[{"t":"list_item","d":7,"p":{},"v":"无状态服务器：没有保留任何状态信息"},{"t":"list_item","d":7,"p":{},"v":"状态服务器：维护状态信息的服务器"}]},{"t":"list_item","d":5,"p":{},"v":"状态问题源于对确保可靠性的要求，特别对无连接传输"},{"t":"list_item","d":5,"p":{},"v":"若传输协议无法保证可靠，应用协议的设计必须保证可靠","c":[{"t":"list_item","d":7,"p":{},"v":"实现服务器如果有状态依赖，必须慎重"}]},{"t":"list_item","d":5,"p":{},"v":"优化无状态服务器","c":[{"t":"list_item","d":7,"p":{},"v":"无连接服务器允许客户从服务器机器磁盘上读出文件","c":[{"t":"list_item","d":9,"p":{},"v":"要保持无状态，每次客户请求都必须指定文件名，文件中的位置，读取的字节数"}]},{"t":"list_item","d":7,"p":{},"v":"设计服务器时，要注意：","c":[{"t":"list_item","d":9,"p":{},"v":"文件打开和关闭的额外开销较高"},{"t":"list_item","d":9,"p":{},"v":"使用该服务器的客户请求可能只读十来字节"},{"t":"list_item","d":9,"p":{},"v":"客户通常按顺序读取文件数据"},{"t":"list_item","d":9,"p":{},"v":"服务器从内存缓冲区读取数据比磁盘快得多"}]},{"t":"list_item","d":7,"p":{},"v":"优化服务器性能维护一个小的文件信息表","c":[{"t":"list_item","d":9,"p":{},"v":"使用ip地址和端口号索引"},{"t":"list_item","d":9,"p":{},"v":"沿缓存指针，从缓存中读取数据而不必打开文件"}]},{"t":"list_item","d":7,"p":{},"v":"上述信息表格可能改善服务器性能"},{"t":"list_item","d":7,"p":{},"v":"需要程序员小心：检测文件名等。。。"},{"t":"list_item","d":7,"p":{},"v":"如果客户出现了故障重新启动，将会重新获得一个不同的端口号，先前的表项将会失去作用，最终会耗尽服务器资源"},{"t":"list_item","d":7,"p":{},"v":"服务器可以选择删除LRU(最近最少使用)但是如果客户经常崩溃，可以能让服务器删除一个合法的用户条目","c":[{"t":"list_item","d":9,"p":{},"v":"优化无状态服务器的使用，程序员必须小心"},{"t":"list_item","d":9,"p":{},"v":"如果客户经常崩溃/重启，或者网络报文重复或者延迟，管理少量状态信息也会消耗资源"}]}]}]},{"t":"heading","d":3,"p":{},"v":"基本类型服务器","c":[{"t":"list_item","d":5,"p":{},"v":"循环/并发"},{"t":"list_item","d":5,"p":{},"v":"连接/无连接传输"},{"t":"list_item","d":5,"p":{},"v":"排列组合为四组类型服务器"}]},{"t":"heading","d":3,"p":{},"v":"请求处理时间","c":[{"t":"list_item","d":5,"p":{},"v":"循环服务器时最简单的，客户按照顺序等待。是否能够满足要求取决于所需的反应时间"},{"t":"list_item","d":5,"p":{},"v":"观测响应时间：客户发送请求到服务器响应之间的全部时延"},{"t":"list_item","d":5,"p":{},"v":"请求处理时间：服务器处理单个请求所花费的时间"},{"t":"list_item","d":5,"p":{},"v":"当服务器有一个队列的请求需要处理时，观测响应时间&gt;&gt;请求处理时间"},{"t":"list_item","d":5,"p":{},"v":"循环服务器一次处理一个请求。如果服务器正在处理一个请求，新到的请求则需要排队等待"},{"t":"list_item","d":5,"p":{},"v":"循环服务器性能：如果一个服务器设计处理K各客户，每个客户每秒发送r各请求，服务器处理时间必须小于每请求1/KR秒。否则请求队列将溢出，考虑并发实现"}]},{"t":"heading","d":3,"p":{},"v":"循环面向连接的服务器算法","c":[{"t":"bullet_list","d":4,"p":{},"v":"","c":[{"t":"list_item","d":5,"p":{},"v":"要求可靠传输的，对每个请求处理少的服务，较常见"}]},{"t":"ordered_list","d":4,"p":{"start":1},"v":"","c":[{"t":"list_item","d":5,"p":{"index":1},"v":"1. 创建套接字并将其绑定到它所提供服务的熟知端口上；"},{"t":"list_item","d":5,"p":{"index":2},"v":"2. 将该端口设置为被动模式，使其准备为服务器所用"},{"t":"list_item","d":5,"p":{"index":3},"v":"3. 从该套接字上接收下一个连接请求，获得该连接的新的套接字"},{"t":"list_item","d":5,"p":{"index":4},"v":"4. 重复地读取来自客户的请求，构造响应，按照应用协议向客户发回响应"},{"t":"list_item","d":5,"p":{"index":5},"v":"5. 当某个特定客户完成交互式，关闭连接返回3.以接受新的连接"}]}]},{"t":"heading","d":3,"p":{},"v":"用INADDR_ANY绑定服务器IP","c":[{"t":"list_item","d":5,"p":{},"v":"服务器需要创建套接字并将其绑定到所熟知的端口上","c":[{"t":"list_item","d":7,"p":{},"v":"getportbyname:服务器名映射到熟知端口上"},{"t":"list_item","d":7,"p":{},"v":"bing：为某个套接字指明某个端点，使用结构sockaddr_in，该结构含有IP地址和端口号"},{"t":"list_item","d":7,"p":{},"v":"对于多接口主机使用INADDR_ANY指明了一个通配地址，让该主机的任何一个IP地址都匹配"}]}]},{"t":"heading","d":3,"p":{},"v":"将套接字置于被动模式","c":[{"t":"list_item","d":5,"p":{},"v":"调用listen：将套接字置于被动模式","c":[{"t":"list_item","d":7,"p":{},"v":"一个参数指明套接字内部的请求队列长度"},{"t":"list_item","d":7,"p":{},"v":"请求队列保存一组TCP传入连接请求，来自客户。都向这个服务器请求一个连接"}]},{"t":"list_item","d":5,"p":{},"v":"接收连接并使用这些连接"},{"t":"list_item","d":5,"p":{},"v":"调用accept：获得下一个传入连接请求","c":[{"t":"list_item","d":7,"p":{},"v":"返回新的连接的套接字的描述符"}]},{"t":"list_item","d":5,"p":{},"v":"服务器接收连接，使用read获得来自客户的应用协议，使用write发回应答"},{"t":"list_item","d":5,"p":{},"v":"服务器结束连接，使用close释放套接字"}]},{"t":"heading","d":3,"p":{},"v":"无连接循环服务器算法","c":[{"t":"list_item","d":5,"p":{},"v":"对每个请求的处理少，无状态的，最常见的"},{"t":"list_item","d":5,"p":{},"v":"循环服务器的设计，编程，排错，修改很容易。往往使用无连接的协议"},{"t":"list_item","d":5,"p":{},"v":"循环服务器对于小的处理时间的服务工作很好。"},{"t":"list_item","d":5,"p":{},"v":"无连接服务器算法：","c":[{"t":"list_item","d":7,"p":{},"v":"创建sock并将其绑定到提供服务的熟知端口上"},{"t":"list_item","d":7,"p":{},"v":"重复读取来自客户的请求，构造响应，按照应用协议向客户发回响应"}]},{"t":"list_item","d":5,"p":{},"v":"构造应答","c":[{"t":"list_item","d":7,"p":{},"v":"connect函数限制了套接字的使用"},{"t":"list_item","d":7,"p":{},"v":"无连接服务器使用sendto:指明了发送的数据报和它将去的地址","c":[{"t":"list_item","d":9,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">retcode <span class=\"token operator\">=</span> <span class=\"token function\">sendto</span><span class=\"token punctuation\">(</span>s<span class=\"token punctuation\">,</span> msg<span class=\"token punctuation\">,</span> len<span class=\"token punctuation\">,</span> flags<span class=\"token punctuation\">,</span> toaddr<span class=\"token punctuation\">,</span> toaddrlen<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</code></pre>\n"}]},{"t":"list_item","d":7,"p":{},"v":"服务器从收到的请求中的源地址获得应答的地址。调用recvfrom得到数据和对方的地址","c":[{"t":"list_item","d":9,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">retcode <span class=\"token operator\">=</span> <span class=\"token function\">recvfrom</span><span class=\"token punctuation\">(</span>s<span class=\"token punctuation\">,</span> buf<span class=\"token punctuation\">,</span> len<span class=\"token punctuation\">,</span> flags<span class=\"token punctuation\">,</span> from<span class=\"token punctuation\">,</span> fromlen<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</code></pre>\n"}]}]}]},{"t":"heading","d":3,"p":{},"v":"并发服务器的算法","c":[{"t":"list_item","d":5,"p":{},"v":"在以下场合并发将会缩短反应时间，给多个客户提供快速响应","c":[{"t":"list_item","d":7,"p":{},"v":"构造要求有相当的I/O时间的响应"},{"t":"list_item","d":7,"p":{},"v":"可以部分重叠的使用处理器和外设"},{"t":"list_item","d":7,"p":{},"v":"各个请求所要求的而处理器处理那些只要求少量处理的请求尽快完成"},{"t":"list_item","d":7,"p":{},"v":"服务器运行在具有多个处理器的计算机上，不同的处理器处理不同的请求"}]},{"t":"list_item","d":5,"p":{},"v":"并发服务器通过使处理和I/O部分重叠来达到高性能。"}]},{"t":"heading","d":3,"p":{},"v":"主线程和从线程","c":[{"t":"list_item","d":5,"p":{},"v":"尽管可以使用一个单线程实现并发服务器，但是大多数使用多线程"},{"t":"list_item","d":5,"p":{},"v":"主线程最先开始执行在熟知的端口上打开一个套接字，等待一个请求，并为每个请求创建一个从线程（可能在一个新进程中）"},{"t":"list_item","d":5,"p":{},"v":"主线程不与客户直接通信，每个从线程处理一个客户的通信"},{"t":"list_item","d":5,"p":{},"v":"从线程构成响应并发送给客户后，这个从线程便退出"}]},{"t":"heading","d":3,"p":{},"v":"并发的无连接服务器算法","c":[{"t":"list_item","d":5,"p":{},"v":"不常见，为每个请求创建一个新线程或进程"},{"t":"list_item","d":5,"p":{},"v":"最简单算法","c":[{"t":"list_item","d":7,"p":{},"v":"主1、创建套接字并将其绑定到所提供服务的熟知地址上。让该套接字保持为未连接的"},{"t":"list_item","d":7,"p":{},"v":"主2、反复调用recvfrom接收来自客户的下一个请求，创建一个新的从线程来处理响应"},{"t":"list_item","d":7,"p":{},"v":"从1、从来自主进程的特定请求以及到该套接字的访问开始"},{"t":"list_item","d":7,"p":{},"v":"从2、根据应用协议构造应答，并用sendto将该应答发回给客户"},{"t":"list_item","d":7,"p":{},"v":"从3、退出（即：从线程处理完一个请求后就终止）"}]},{"t":"list_item","d":5,"p":{},"v":"由于创建进程或者线程是昂贵的，因此只有很少的无连接服务器采用并发实现"}]},{"t":"heading","d":3,"p":{},"v":"并发的面向连接服务器算法","c":[{"t":"list_item","d":5,"p":{},"v":"最一般的。可靠传输，并发处理多个请求"},{"t":"list_item","d":5,"p":{},"v":"多进程可以是多个独立的程序"},{"t":"list_item","d":5,"p":{},"v":"多线程（进程）或者单线程方式"},{"t":"list_item","d":5,"p":{},"v":"面向连接的服务器在多个连接之间实现并发"},{"t":"list_item","d":5,"p":{},"v":"主1、创建套接字并将其绑定到所提供服务的熟知地址上。让该套接字保持为面向连接"},{"t":"list_item","d":5,"p":{},"v":"主2、将该端口设置为被动模式"},{"t":"list_item","d":5,"p":{},"v":"主3、反复调用accept以便接收来自客户的下一个连接请求，并创建新的从线程或者进程来处理响应"},{"t":"list_item","d":5,"p":{},"v":"从1、由主线程传递来的连接请求开始"},{"t":"list_item","d":5,"p":{},"v":"从2、用该连接与客户进行交互；读取请求并发回响应"},{"t":"list_item","d":5,"p":{},"v":"从3、关闭连接并退出"}]},{"t":"heading","d":3,"p":{},"v":"服务器并发性的实现","c":[{"t":"list_item","d":5,"p":{},"v":"两种i形式的并发性：进程/线程"},{"t":"list_item","d":5,"p":{},"v":"服务器创建多个进程，每个进程都有一个执行线程"},{"t":"list_item","d":5,"p":{},"v":"服务器在一个进程中创建多个执行线程"},{"t":"list_item","d":5,"p":{},"v":"<img src=\"./tcpIp_5.png\" alt=\"并发程\">"},{"t":"list_item","d":5,"p":{},"v":"单独程序作为进程使用","c":[{"t":"list_item","d":7,"p":{},"v":"并发服务器为每个连接创建一个新从线程","c":[{"t":"list_item","d":9,"p":{},"v":"对于单线程的进程实现，采用fork实现"},{"t":"list_item","d":9,"p":{},"v":"程序中包含主进程和从进程的全部代码"}]},{"t":"list_item","d":7,"p":{},"v":"从进程执行一个单独编写和编译的程序也许更加方便","c":[{"t":"list_item","d":9,"p":{},"v":"linux系统支持"},{"t":"list_item","d":9,"p":{},"v":"调用fork后再execve"}]}]},{"t":"list_item","d":5,"p":{},"v":"程序中包含主从进程的全部代码","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">include</span> <span class=\"token string\">&lt;stdlib.h></span></span>\n<span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">include</span> <span class=\"token string\">&lt;stdio.h></span></span>\n<span class=\"token keyword\">int</span> mul<span class=\"token punctuation\">,</span>sum<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">int</span> <span class=\"token function\">main</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">int</span> i<span class=\"token punctuation\">,</span>pid<span class=\"token punctuation\">;</span>\n    sum <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\n    mul <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>pid<span class=\"token operator\">=</span><span class=\"token function\">fork</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">></span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>    <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">for</span><span class=\"token punctuation\">(</span>i<span class=\"token operator\">=</span><span class=\"token number\">1</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">&lt;=</span><span class=\"token number\">5</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span>     <span class=\"token punctuation\">{</span>\n            <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"The value of i is %d\\n\"</span><span class=\"token punctuation\">,</span>i<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token function\">fflush</span><span class=\"token punctuation\">(</span><span class=\"token constant\">stdout</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            sum <span class=\"token operator\">+=</span> i<span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"The sum is %d\\n\"</span><span class=\"token punctuation\">,</span>sum<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token comment\">//父进程</span>\n    <span class=\"token keyword\">else</span> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>pid <span class=\"token operator\">==</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>    <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span>i<span class=\"token operator\">=</span><span class=\"token number\">1</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">&lt;=</span><span class=\"token number\">5</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span>        <span class=\"token punctuation\">{</span>\n            <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"The value of i is %d\\n\"</span><span class=\"token punctuation\">,</span>i<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token function\">fflush</span><span class=\"token punctuation\">(</span><span class=\"token constant\">stdout</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            mul <span class=\"token operator\">*=</span> i<span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"The multiplex is %d\\n\"</span><span class=\"token punctuation\">,</span>mul<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token comment\">//从进程</span>\n   <span class=\"token function\">exit</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"从进程执行一个单独编写和编译的程序","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> sum<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">int</span> <span class=\"token function\">main</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">int</span> i<span class=\"token punctuation\">,</span>pid<span class=\"token punctuation\">;</span>\n    mul <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>pid<span class=\"token operator\">=</span><span class=\"token function\">fork</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">></span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>    <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">for</span><span class=\"token punctuation\">(</span>i<span class=\"token operator\">=</span><span class=\"token number\">1</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">&lt;=</span><span class=\"token number\">5</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span>     <span class=\"token punctuation\">{</span>\n            <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"The value of i is %d\\n\"</span><span class=\"token punctuation\">,</span>i<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token function\">fflush</span><span class=\"token punctuation\">(</span><span class=\"token constant\">stdout</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            sum <span class=\"token operator\">+=</span> i<span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token function\">printf</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"The sum is %d\\n\"</span><span class=\"token punctuation\">,</span>sum<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token comment\">//父进程</span>\n     <span class=\"token keyword\">else</span> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>pid <span class=\"token operator\">==</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span> <span class=\"token function\">execl</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"./mul\"</span><span class=\"token punctuation\">,</span><span class=\"token string\">\"./mul\"</span><span class=\"token punctuation\">,</span><span class=\"token constant\">NULL</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n     <span class=\"token keyword\">else</span>\n        <span class=\"token function\">exit</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">exit</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n"}]}]},{"t":"heading","d":3,"p":{},"v":"使用单线程获得表面上的并发性","c":[{"t":"list_item","d":5,"p":{},"v":"使用单个线程来处理客户的请求的意义","c":[{"t":"list_item","d":7,"p":{},"v":"操作系统创建线程或者进程的开销太昂贵"},{"t":"list_item","d":7,"p":{},"v":"许多应用要求服务器在多个连接中共享信息"}]},{"t":"list_item","d":5,"p":{},"v":"X窗口系统使用显示缓存作为共享数据结构，给各个窗口的显示提供表面并发","c":[{"t":"list_item","d":7,"p":{},"v":"出现在服务器的请求没有超过服务器的处理能力"},{"t":"list_item","d":7,"p":{},"v":"单线程的服务器使用select系统调用进行异步I/O"}]},{"t":"list_item","d":5,"p":{},"v":"处理多连接的算法","c":[{"t":"list_item","d":7,"p":{"index":1},"v":"1. 创建套接字并将其绑定到这个服务的熟知端口上，将该套接字加到一个表中，该表中的项是可以进行I/O的描述符。"},{"t":"list_item","d":7,"p":{"index":2},"v":"2. 使用select在已经有的套接字上等待I/O"},{"t":"list_item","d":7,"p":{"index":3},"v":"3. 如果最初的套接字准备就绪，使用accept获得下一个连接，并将这个新的套接字加入到表中，该表中的项是可以进行I/O的描述符。"},{"t":"list_item","d":7,"p":{"index":4},"v":"4. 如果最初的套接字以外的套接字就绪，就使用recv或read获得下一个请求，构造响应，用send或者write将响应发回给客户"},{"t":"list_item","d":7,"p":{"index":5},"v":"5. 继续按照以上的步骤2进行处理"}]}]},{"t":"heading","d":3,"p":{},"v":"各个服务器使用的场合","c":[{"t":"list_item","d":5,"p":{},"v":"循环的和并发的","c":[{"t":"list_item","d":7,"p":{},"v":"如果循环方案产生的响应时间对应用来说足够，就可以使用循环；否则需要并发"}]},{"t":"list_item","d":5,"p":{},"v":"真正的和表面的并发","c":[{"t":"list_item","d":7,"p":{},"v":"创建线程或切换环境的开销大，服务器需要在多个连接之间共享或者交换数据，用单线程"},{"t":"list_item","d":7,"p":{},"v":"使用线程开销不大，服务器需要在多个连接之间共享或者交换数据，用多线程"},{"t":"list_item","d":7,"p":{},"v":"每个进程可以孤立运行或者要得到最大并发性，使用多进程"}]},{"t":"list_item","d":5,"p":{},"v":"面向连接和无连接","c":[{"t":"list_item","d":7,"p":{},"v":"当应用协议处理了可靠性问题，或者应用在局域网环境内时，使用无连接的传输。否则使用有连接传输"}]}]},{"t":"heading","d":3,"p":{},"v":"服务器死锁","c":[{"t":"list_item","d":5,"p":{},"v":"循环的面向连接的服务器","c":[{"t":"list_item","d":7,"p":{},"v":"某个客户和服务器建立一个连接，客户不再发送请求，服务器无法使用recv得到请求，服务器将在这里阻塞客户不能正常工作，不处理服务器的响应，将致","c":[{"t":"list_item","d":9,"p":{},"v":"客户接收窗口填满，而服务器的外发存储数据区填满阻塞"}]}]},{"t":"list_item","d":5,"p":{},"v":"可能阻塞的系统调用会产生死锁","c":[{"t":"list_item","d":7,"p":{},"v":"如没有本地缓存时（发方存放已发数据，收方存放待收数据），发送方send或者write会阻塞；接收方recv或者read调用也将阻塞"},{"t":"list_item","d":7,"p":{},"v":"单线程的服务器会被阻塞死锁"}]}]}]},{"t":"heading","d":2,"p":{},"v":"循环服务器详解","c":[{"t":"heading","d":3,"p":{},"v":"概述","c":[{"t":"bullet_list","d":4,"p":{},"v":"","c":[{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">循环服务器的类型\n循环无连接服务器\n使用无连接的循环服务器，采用算法<span class=\"token number\">8.2</span>\nTIME服务的例子\n循环面向连接的服务器\n循环的面向连接的服务器，采用算法<span class=\"token number\">8.1</span>\nDAYTIME服务的例子\n特点：\n每次处理时间都很少\n服务器实现简单\n</code></pre>\n"}]},{"t":"ordered_list","d":4,"p":{"start":1},"v":"","c":[{"t":"list_item","d":5,"p":{"index":1},"v":"1. 创建被动套接字","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">创建一个过程隐藏创建一个被动套接字的细节\npassiveUDP<span class=\"token operator\">:</span> 本章学习，使用无连接的被动套接字\npassiveTCP<span class=\"token operator\">:</span> 使用面向连接的被动套接字\n获得熟知的端口号，端口号的唯一性问题。\n使用什么协议\n绑定IP地址\n使用全局变量portbase的优点\n安全性：不修改程序中引用端口的地方导致少发生错误\n通用性：允许测试的时候，多个服务器版本共存运行，portbase的值不一样，测试版本的端口不会冲突\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">passiveUDP\n调用passivesock实现\npassiveTCP\n调用passivesock实现\npassivesock\n三个参数\n第一个服务名，第二个协议名，第三个参数指明连接请求队列所需要的长度（只用于TCP套接字）\n使用INADDR_ANY代替特定的本地IP地址\ngetservbyname<span class=\"token punctuation\">,</span> getprotobyname<span class=\"token punctuation\">,</span> strcmp<span class=\"token punctuation\">,</span> memset<span class=\"token punctuation\">,</span> socket<span class=\"token punctuation\">,</span> bind<span class=\"token punctuation\">,</span> listen…\n分析passivesock<span class=\"token punctuation\">.</span>c\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{"index":2},"v":"2. 循环无连接服务器算法8.2","c":[{"t":"list_item","d":7,"p":{"index":1},"v":"1. 只需要一个执行线程"},{"t":"list_item","d":7,"p":{"index":2},"v":"2. <img src=\"./tcpIp_6.png\" alt=\"结构\">"}]}]},{"t":"bullet_list","d":4,"p":{},"v":"","c":[{"t":"list_item","d":5,"p":{},"v":"time服务器","c":[{"t":"list_item","d":7,"p":{},"v":"几乎不需要计算"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">UDPtimed<span class=\"token punctuation\">.</span>c page91\n头文件include\n宏定义，变量定义，函数声明\nmain函数\n参数分析\n调用passiveUDP\nrecvfrom，sendto循环\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"小结","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">使用这个服务器的原因\n    简单服务\n    服务器为每个请求的计算很少\n    循环服务器是个简单的服务器\n建立被动的套接字的过程\n    TIME服务\n    获得系统时间服务\n    使用UDP访问\n    编程方法\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"循环的面向连接的服务器","c":[{"t":"list_item","d":9,"p":{},"v":"分配被动的TCP套接字","c":[{"t":"list_item","d":11,"p":{},"v":"调用passiceTCP实现"},{"t":"list_item","d":11,"p":{},"v":"带有两个参数"},{"t":"list_item","d":11,"p":{},"v":"第一个是字符串：服务的名字或者端口号"},{"t":"list_item","d":11,"p":{},"v":"第二个：传入连接的请求队列所需的长度"}]}]}]}]}]},{"t":"heading","d":3,"p":{},"v":"用于DAYTIME服务的服务器","c":[{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">DAYTIME服务：从另外机器上获得当前的日期和时间（前面第<span class=\"token number\">7</span>章已经谈过）\nDAYTIME服务器不需要优化速率\n获取和格式化日期要求很少的处理\n用户对此服务的需求很少\n循环实现就足够了\n服务器忙的时候，其他的请求可以排队\n</code></pre>\n"},{"t":"list_item","d":5,"p":{},"v":"结构","c":[{"t":"list_item","d":7,"p":{},"v":"使用一个单执行线程"},{"t":"list_item","d":7,"p":{},"v":"使用两个套接字","c":[{"t":"list_item","d":9,"p":{},"v":"一个套接字处理请求"},{"t":"list_item","d":9,"p":{},"v":"另外一个套接字处理和客户的通信（临时的）"}]},{"t":"list_item","d":7,"p":{},"v":"<img src=\"./tcpIp_7.png\" alt=\"结构\">"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">TCPdaytimed<span class=\"token punctuation\">.</span>c   page96\npassiveTCP隐藏了很多套接字分配和绑定的细节\nQLEN<span class=\"token operator\">:</span>客户连接请求等待队列长度\n在循环中，使用accept从主套接字得到一个连接（accept完成三次握手过程）\n对于新的连接服务器调用过程TCPdaytimed进行处理\n处理完毕继续循环，再次调用accept阻塞\n\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"关闭连接","c":[{"t":"list_item","d":9,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">调用TCPdaytimed返回后，主程序关闭该连接的套接字\n调用close是从容关闭：TCP保证所有的数据可靠交付给客户（连接终止前收到确认）\nclose不能立刻返回，调用将会阻塞，直到收到客户的确认\n\n</code></pre>\n"}]},{"t":"list_item","d":7,"p":{},"v":"连接终止问题","c":[{"t":"list_item","d":9,"p":{},"v":"DAYTIME服务器知道何时应该终止连接"},{"t":"list_item","d":9,"p":{},"v":"复杂客户服务器系统的应用，必须了解客户什么时候是最后一个请求，客户必须发送一个完成的信号"}]},{"t":"list_item","d":7,"p":{},"v":"允许客户控制连接时间有危险:服务器的脆弱性","c":[{"t":"list_item","d":9,"p":{},"v":"误操作的客户可能导致服务器消耗掉套接字和TCP连接相关的资源"},{"t":"list_item","d":9,"p":{},"v":"客户快速的重复的发出请求，可以把服务器的资源用光"}]}]},{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">循环的面向连接的服务器每处理一个连接循环一次\n    连接达到以前在accept阻塞\n    建立新的连接以后创建新套接字处理\n    处理完毕，关闭，返回accept阻塞\nDAYTIME服务\n    不需要客户的请求信息，检测到连接就响应\n    发送完响应，服务器主动关闭连接\n    每个连接只发送一个响应\n\n</code></pre>\n"}]}]},{"t":"heading","d":2,"p":{},"v":"并发服务器","c":[{"t":"bullet_list","d":3,"p":{},"v":"","c":[{"t":"list_item","d":4,"p":{},"v":"概述","c":[{"t":"list_item","d":6,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">并发的面向连接的服务器\n采用算法<span class=\"token number\">8.4</span>的最常用的服务器设计\n主服务器进程在机器启动的时候自动一直运行，对每个客户的新连接创建一个新的从线程<span class=\"token operator\">/</span>进程进行处理\n并发ECHO的例子\n多进程（每个含一个线程）设计的并发服务器\n多线程（属于同一个进程）设计的并发服务器\n单线程设计的并发服务器\n</code></pre>\n"}]},{"t":"list_item","d":4,"p":{},"v":"并发ECHO","c":[{"t":"list_item","d":6,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">功能：\n客户打开到某个服务器的连接，然后在该连接上重复发送数据，并读取从服务器返回的回显，\n服务器响应每个客户，接受连接，读取来自该客户的数据，并原样返回给客户。\n服务器在发送响应前并非读取全部输入，只是交替读写\n服务器在遇到文件结束的条件后，关闭连接\n</code></pre>\n"}]},{"t":"list_item","d":4,"p":{},"v":"循环与并发实现比较","c":[{"t":"list_item","d":6,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">如果使用循环服务器实现\n    某些客户可能发送大量的数据，导致其他的客户延迟\n使用并发服务器实现\n    避免了长时间的延迟，不允许单个客户占用所有的资源\n    使服务器与许多客户同时进行通信\n    客户感觉服务器提供了较短的响应时间\n</code></pre>\n"}]},{"t":"list_item","d":4,"p":{},"v":"进程结构","c":[{"t":"list_item","d":6,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">服务器包括一个主进程，以及零个或者多个从进程。每个进程一个线程\n主服务器使用accept阻塞调用，节约CPU资源，连接到来的时候，accept马上返回。\n</code></pre>\n"},{"t":"list_item","d":6,"p":{},"v":"<img src=\"./tcpIp_8.png\" alt=\"jiegou\">"}]}]},{"t":"heading","d":3,"p":{},"v":"并发ECHO服务器举例","c":[{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token macro property\"><span class=\"token directive-hash\">#</span><span class=\"token directive keyword\">include</span> <span class=\"token expression\">语句</span></span>\n变量定义，宏定义，函数声明\n主函数\n    参数处理\n    建立被动套接字\n    循环等待连接，如果有新连接，则fork一个新的线程，调用TCPechod进行处理\nTCPechod函数\n    处理echo服务\n</code></pre>\n"},{"t":"list_item","d":5,"p":{},"v":"注意：代码中关闭套接字的方式和原因，否则有可能出现有时候子进程退出,父进程的sock进行accept时,不能返回"},{"t":"list_item","d":5,"p":{},"v":"和循环单进程服务器代码的比较"}]},{"t":"heading","d":3,"p":{},"v":"清除游离进程","c":[{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">使用fork的服务器动态生成进程，可能导致不完全的进程终止\n    linux在一个子进程退出的时候，会给父进程一个信号（signal<span class=\"token punctuation\">)</span>\n    正在退出的进程保持在死状态，直到父进程执行wait3系统调用为止\n    signal（SIGCHLD<span class=\"token punctuation\">,</span> reaper<span class=\"token punctuation\">)</span>主服务器进程收到子进程退出信号的时候，执行函数reaper\n    函数reaper调用函数wait3完成子进程的终止并退出。\n      参数WNOHANG指明wait3不要为了进程退出而阻塞等待\n</code></pre>\n"},{"t":"list_item","d":5,"p":{},"v":"扩展-僵尸进程","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">在<span class=\"token function\">fork</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token operator\">/</span><span class=\"token function\">execve</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>过程中，假设子进程结束时父进程仍存在，而父进程<span class=\"token function\">fork</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>之前既没安装SIGCHLD信号处理函数调用<span class=\"token function\">waitpid</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>等待子进程结束，又没有显式忽略该信号，则子进程成为僵尸进程，无法正常结束\n    \n一个进程在调用exit命令结束自己的生命的时候，其实它并没有真正的被销毁，而是留下一个称为僵尸进程（Zombie）的数据结构。\n在Linux进程的状态中，僵尸进程是非常特殊的一种，它已经放弃了几乎所有内存空间，没有任何可执行代码，也不能被调度，仅仅在进程列表中保留一个位置，记载该进程的退出状态等信息供其他进程收集，除此之外，僵尸进程不再占有任何内存空间。\n    \n如果他的父进程没安装SIGCHLD信号处理函数调用wait或<span class=\"token function\">waitpid</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>等待子进程结束，又没有显式忽略该信号，那么它就一直保持僵尸状态，直到父进程结束\n\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"僵尸进程的清除","c":[{"t":"list_item","d":9,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token number\">1.</span>修改父进程，在子进程死后要为它收尸。具体做法是接管SIGCHLD信号。子进程死后，会发送SIGCHLD信号给父进程，父进程收到此信号后，执行wait <span class=\"token operator\">/</span><span class=\"token function\">waitpid</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>函数为子进程收尸。这是基于这样的原理：就算父进程没有调用wait，内核也会向它发送SIGCHLD消息，尽管对的默认处理是忽略，如果想响应这个消息，可以设置一个处理函数。 \n　　<span class=\"token number\">2.</span>把父进程杀掉。父进程死后，僵尸进程成为<span class=\"token string\">\"孤儿进程\"</span>，过继给<span class=\"token number\">1</span>号进程init，init始终会负责清理僵尸进程．它产生的所有僵尸进程也跟着消失。\n\n</code></pre>\n"}]}]},{"t":"list_item","d":5,"p":{},"v":"Wait用法","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">//函数原型：</span>\npid_t <span class=\"token function\">wait</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> <span class=\"token operator\">*</span>status<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">/*进程一旦调用了wait就立即阻塞自己，由wait自动分析是否当前进程的某个子进程已经退出，如果让它找到了这样一个已经变成僵尸的子进程，wait就会收集这个子进程的信息，并把它彻底销毁后返回；如果没有找到这样一个子进程，wait就会一直阻塞在这里，直到有一个出现为止。\n参数status用来保存被收集进程退出时的一些状态。绝大多数情况下，对这个子进程是如何死掉毫不在意，只想把这个僵尸进程消灭掉，可以：*/</span>\n<span class=\"token function\">wait</span><span class=\"token punctuation\">(</span><span class=\"token constant\">NULL</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"wait()要与fork()配套出现,如果在使用fork()之前调用wait(),wait()的返回值则为-1,正常情况下wait()的返回值为子进程的PID."},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token function\">Wait3</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\npid_t <span class=\"token function\">wait3</span> <span class=\"token punctuation\">(</span> <span class=\"token keyword\">int</span> <span class=\"token operator\">*</span>status<span class=\"token punctuation\">,</span> <span class=\"token keyword\">int</span> option<span class=\"token punctuation\">,</span> <span class=\"token keyword\">struct</span> <span class=\"token class-name\">rusage</span> <span class=\"token operator\">*</span>ru <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">//除了可以获取子进程状态转变信息外，还可以获得子进程的资源使用信息。</span>\n\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token function\">wait4</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\npid_t <span class=\"token function\">wait4</span> <span class=\"token punctuation\">(</span> pid_t pid<span class=\"token punctuation\">,</span> <span class=\"token keyword\">int</span> <span class=\"token operator\">*</span>status<span class=\"token punctuation\">,</span> <span class=\"token keyword\">int</span> option<span class=\"token punctuation\">,</span> <span class=\"token keyword\">struct</span> <span class=\"token class-name\">rusage</span> <span class=\"token operator\">*</span>ru <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">//类似waitpid</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"tips","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">可以fork两次。可以避免再去处理僵尸。\n    父进程产生子进程\n    子进程产生孙进程\n    子进程结束，父进程负责处理\n因为子进程结束，孙进程被挂在init进程上，这样孙进程不需任何处理。\n注意：父进程必须处理子进程。否则子进程还是成为了僵尸\n</code></pre>\n"}]}]},{"t":"heading","d":3,"p":{},"v":"使用线程来实现并发","c":[{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">一个进程中有一个或者多个线程\n  linux中的线程符合POSIX线程标准，<span class=\"token number\">1003.1</span>c\nlinux中线程的特点\n    动态创建：pthread_create，具有上限\n    并发执行：多处理机上可以并行\n    抢先：系统自动在多个线程中调动CPU资源\n    私有局部变量：每个线程有自己的私有堆栈<span class=\"token punctuation\">,</span>存放局部变量\n    共享全局变量：一个进程的所有线程共享全局变量\n    共享文件描述符：一个进程内的所有线程共享一组文件描述符\n    协调和同步函数：具有线程协调和同步执行的函数\n\n</code></pre>\n"},{"t":"list_item","d":5,"p":{},"v":"优点","c":[{"t":"list_item","d":7,"p":{},"v":"线程的进程和单线程的进程比较","c":[{"t":"list_item","d":9,"p":{},"v":"更高的效率：上下文切换的额外开销减少","c":[{"t":"list_item","d":11,"p":{},"v":"上下文切换：线程切换需要执行的指令"},{"t":"list_item","d":11,"p":{},"v":"同一进程中的两个线程比不同进程中的两个线程切换要快"},{"t":"list_item","d":11,"p":{},"v":"进程内的线程切换不用改变虚拟存储器的映射"},{"t":"list_item","d":11,"p":{},"v":"一个进程的开销大约是一个线程开销的30倍左右，当然，在具体的系统上，这个数据可能会有较大的区别。"}]},{"t":"list_item","d":9,"p":{},"v":"共享存储器：","c":[{"t":"list_item","d":11,"p":{},"v":"并发服务器中的多个副本需要相互通信或者访问共享的数据<br>\n利用线程容易构造监控系统"}]}]}]},{"t":"list_item","d":5,"p":{},"v":"缺点","c":[{"t":"list_item","d":7,"p":{},"v":"由于线程间共享存储器和进程状态，一个线程的动作可能对同一个进程内的其他线程产生影响。","c":[{"t":"list_item","d":9,"p":{},"v":"两个线程如果同一时刻访问同一个变量，会产生相互干扰"},{"t":"list_item","d":9,"p":{},"v":"将指针返回给一个静态的数据项的库函数不是线程安全的，覆盖将会导致错误（比如，gethostbyname）"},{"t":"list_item","d":9,"p":{},"v":"缺乏健壮性，一个线程出错，服务器将会终止整个进程"}]}]},{"t":"list_item","d":5,"p":{},"v":"定义与创建","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">/*线程（thread）技术早在60年代就被提出，但真正应用多线程到操作系统中去，是在80年代中期，solaris是这方面的佼佼者。\n创建。 POSIX线程标准*/</span>\npthread_create\n<span class=\"token keyword\">typedef</span> <span class=\"token keyword\">unsigned</span> <span class=\"token keyword\">long</span> <span class=\"token keyword\">int</span> pthread_t<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">extern</span> <span class=\"token keyword\">int</span> pthread_create <span class=\"token function\">__P</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span>pthread_t <span class=\"token operator\">*</span>__thread<span class=\"token punctuation\">,</span> __const pthread_attr_t <span class=\"token operator\">*</span>__attr<span class=\"token punctuation\">,</span>\u000b　　<span class=\"token keyword\">void</span> <span class=\"token operator\">*</span><span class=\"token punctuation\">(</span><span class=\"token operator\">*</span>__start_routine<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">void</span> <span class=\"token operator\">*</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">void</span> <span class=\"token operator\">*</span>__arg<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">/*Linux下pthread的实现是通过系统调用clone（）来实现的。clone（）是Linux所特有的系统调用，它的使用方式类似fork*/</span>\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"线程状态","c":[{"t":"list_item","d":7,"p":{},"v":"分离模式"},{"t":"list_item","d":7,"p":{},"v":"非分离模式"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> <span class=\"token function\">pthread_attr_setdetachstate</span><span class=\"token punctuation\">(</span>pthread_attr_t <span class=\"token operator\">*</span>attr<span class=\"token punctuation\">,</span> <span class=\"token keyword\">int</span> detachstate<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">int</span> <span class=\"token function\">pthread_attr_getdetachstate</span><span class=\"token punctuation\">(</span>pthread_attr_t <span class=\"token operator\">*</span>attr<span class=\"token punctuation\">,</span> <span class=\"token keyword\">int</span> <span class=\"token operator\">*</span>detachstate<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">//detachstate 可指定为下面值：  PTHREAD_CREATE_DETACHED 使用 attr 创建的线程将是独立的。 </span>\n<span class=\"token comment\">//PTHREAD_CREATE_JOINABLE 使用 attr 创建的线程将是可聚合的。</span>\n\n</code></pre>\n"}]},{"t":"list_item","d":5,"p":{},"v":"描述符、延迟和退出","c":[{"t":"list_item","d":7,"p":{},"v":"许多动态分配的资源都是和进程相关的","c":[{"t":"list_item","d":9,"p":{},"v":"一个线程打开某个文件，同一进程的其他线程也可以使用同一个描述符访问文件"},{"t":"list_item","d":9,"p":{},"v":"虽然有些操作系统调用只会影响调用它的线程","c":[{"t":"list_item","d":11,"p":{},"v":"I/O调用阻塞，只影响调用它的线程；"}]},{"t":"list_item","d":9,"p":{},"v":"但是有些系统调用会影响整个进程","c":[{"t":"list_item","d":11,"p":{},"v":"exit函数会让整个进程退出"}]}]},{"t":"list_item","d":7,"p":{},"v":"线程的退出方法","c":[{"t":"list_item","d":9,"p":{},"v":"线程的顶级过程返回时终止该线程"},{"t":"list_item","d":9,"p":{},"v":"调用pthread_exit终止该线程"}]}]}]},{"t":"heading","d":3,"p":{},"v":"线程的协调与同步","c":[{"t":"list_item","d":5,"p":{},"v":"线程协调和同步是必要的","c":[{"t":"list_item","d":7,"p":{},"v":"线程可能被阻塞"},{"t":"list_item","d":7,"p":{},"v":"线程的同步机制：互斥，信号量，条件变量"}]},{"t":"list_item","d":5,"p":{},"v":"互斥","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">//对共享数据的排他性访问</span>\npthread_mutex_init<span class=\"token comment\">//,产生并初始化一个互斥</span>\npthread_mutex_lock<span class=\"token comment\">//, 使用共享数据前调用</span>\npthread_mutex_unlock<span class=\"token comment\">//，使用共享数据后释放</span>\n\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"工作方式","c":[{"t":"list_item","d":9,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">pthread_mutex_lock声明开始用互斥锁上锁，此后的代码直至调用pthread_mutex_unlock为止，均被上锁，即同一时间只能被一个线程调用执行。当一个线程执行到pthread_mutex_lock处时，如果该锁此时被另一个线程使用，那此线程被阻塞，即程序将等待到另一个线程释放此互斥锁。\n</code></pre>\n"}]}]},{"t":"list_item","d":5,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">void</span> <span class=\"token function\">reader_function</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">void</span> <span class=\"token function\">writer_function</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">char</span> buffer<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">int</span> buffer_has_item <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\npthread_mutex_t mutex<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">struct</span> <span class=\"token class-name\">timespec</span> delay<span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">void</span> <span class=\"token function\">main</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    pthread_t reader<span class=\"token punctuation\">;</span> <span class=\"token comment\">/* 定义延迟时间*/</span>\n    delay<span class=\"token punctuation\">.</span>tv_sec <span class=\"token operator\">=</span> <span class=\"token number\">2</span><span class=\"token punctuation\">;</span>\n    delay<span class=\"token punctuation\">.</span>tv_nec <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">/* 用默认属性初始化一个互斥锁对象*/</span>\n    <span class=\"token function\">pthread_mutex_init</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>mutex<span class=\"token punctuation\">,</span> <span class=\"token constant\">NULL</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">pthread_create</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>reader<span class=\"token punctuation\">,</span> pthread_attr_default<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">void</span> <span class=\"token operator\">*</span><span class=\"token punctuation\">)</span><span class=\"token operator\">&amp;</span>reader_function<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">NULL</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">writer_function</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">void</span> <span class=\"token function\">writer_function</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">while</span> <span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span> <span class=\"token comment\">/* 锁定互斥锁*/</span>\n        <span class=\"token function\">pthread_mutex_lock</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>mutex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>buffer_has_item <span class=\"token operator\">==</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">{</span>\n            buffer <span class=\"token operator\">=</span> <span class=\"token function\">make_new_item</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            buffer_has_item <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span> <span class=\"token comment\">/* 打开互斥锁*/</span>\n        <span class=\"token function\">pthread_mutex_unlock</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>mutex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token function\">pthread_delay_np</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>delay<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">void</span> <span class=\"token function\">reader_function</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">void</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">while</span> <span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token function\">pthread_mutex_lock</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>mutex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>buffer_has_item <span class=\"token operator\">==</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">{</span>\n            <span class=\"token function\">consume_item</span><span class=\"token punctuation\">(</span>buffer<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            buffer_has_item <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token function\">pthread_mutex_unlock</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>mutex<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token function\">pthread_delay_np</span><span class=\"token punctuation\">(</span><span class=\"token operator\">&amp;</span>delay<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n</code></pre>\n"},{"t":"list_item","d":5,"p":{},"v":"线程的协调与同步","c":[{"t":"list_item","d":7,"p":{},"v":"信号量：同步机制","c":[{"t":"list_item","d":9,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token comment\">//由于系统中有N个资源可用的情况允许N个线程同时执行使用</span>\nsem_init<span class=\"token comment\">//，初始化一个信号量</span>\nsem_wait<span class=\"token comment\">//,  线程使用一个资源前必须调用</span>\nsem_post<span class=\"token comment\">//，使用完后返还资源</span>\n</code></pre>\n"}]},{"t":"list_item","d":7,"p":{},"v":"条件变量","c":[{"t":"list_item","d":9,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">最复杂和难以理解的一种同步机制\n    一组线程使用互斥对同一个资源提供排它性访问。\n    一旦某个线程获得资源，它需要等待一个特定的条件发生\n</code></pre>\n"},{"t":"list_item","d":9,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">pthread_cond_wait<span class=\"token operator\">:</span> 同时指定了等待的条件变量和所拥有的互斥，执行后阻塞。\npthread_cond_signal只允许一个线程继续执行\npthread_cond_broadcast允许多个线程继续执行\n等待条件变量的时候要暂时放弃互斥\n得到条件变量的时候自动重新获得互斥\n\n</code></pre>\n"},{"t":"list_item","d":9,"p":{},"v":""}]}]},{"t":"list_item","d":5,"p":{},"v":"使用线程服务器实例","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">多线程的ECHO服务\n并发的面向连接的算法\n连接到达后，调用pthread_create创建一个新的线程来处理连接。\n新线程执行TCPechod过程。\nTCPmtechod<span class=\"token punctuation\">.</span>c  page110\n线程处理函数\n统计结构的互斥使用\n互斥处理函数\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"监控"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">采用一个独立的线程prstats打印统计信息\n    每睡眠INTERVAL打印一次\n    监控线程和从线程使用一个共享的全局数据结构：stats相互通信\n    采用互斥的机制：stats<span class=\"token punctuation\">.</span>st_mutex\n实际的服务器监控程序可以让管理员以更加复杂的形式和服务器交互\n    可以控制服务器\n    可以按需提供信息\n    可以得到更加全面的信息\n\n</code></pre>\n"}]}]},{"t":"heading","d":3,"p":{},"v":"单线程并发处理器","c":[{"t":"bullet_list","d":4,"p":{},"v":"","c":[{"t":"list_item","d":5,"p":{},"v":"大多数并发服务器使用前面提供的两种方法，使用操作系统的设施创建独立的进程或者线程，利用分时来占用处理器"},{"t":"list_item","d":5,"p":{},"v":"使用单线程也可以提供表面上的并发性"},{"t":"list_item","d":5,"p":{},"v":"服务器中的数据驱动处理","c":[{"t":"list_item","d":7,"p":{},"v":"对一个请求的响应中如果I/O占了主导地位，服务器可以使用异步I/O来实现表面并发性，使用数据触发处理。"},{"t":"list_item","d":7,"p":{},"v":"ECHO服务器","c":[{"t":"list_item","d":9,"p":{},"v":"理论上是时间分片机制让多线程共享CPU"},{"t":"list_item","d":9,"p":{},"v":"实际上是数据的到达控制了处理的进行"},{"t":"list_item","d":9,"p":{},"v":"每个从线程大部分时间花在read的阻塞上"}]},{"t":"list_item","d":7,"p":{},"v":"若并发服务器处理每个请求仅需要很少时间，可以由数据到达驱动。"},{"t":"list_item","d":7,"p":{},"v":"在工作量太大，以致CPU不能顺序执行的时候，分时机制才取而代之"}]},{"t":"list_item","d":5,"p":{},"v":"用单线程进行数据驱动处理","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">打开许多客户的TCP连接\n线程阻塞等待数据的到达\n任何一个连接上有数据到达，线程就被唤醒\n处理请求，发送响应后，再次阻塞，等待 另一个连接上数据到达\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"同多线程或者多进程比较，可能处理略高些的负荷（因为减少了上下文切换开销）"},{"t":"list_item","d":7,"p":{},"v":"关键是使用OS的select原语实现异步I/O<br>\n算法8.5列出了实现"}]},{"t":"list_item","d":5,"p":{},"v":"单线程、并发服务器的线程和套接字结构","c":[{"t":"list_item","d":7,"p":{},"v":"一个执行线程管理所有的套接字"},{"t":"list_item","d":7,"p":{},"v":"<img src=\"./tcpIp_9.png\" alt=\"jiegou\">"},{"t":"list_item","d":7,"p":{},"v":"单线程服务器必须完成主线程和从线程双方的职责","c":[{"t":"list_item","d":9,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">维护一组套接字\n组中某套接字绑定到接受连接的熟知端口上\n其它套接字对应一个连接\n服务器把这组套接字描述符作为一个参数传递给select，并等待任何一个套接字的活动\n使用描述符来区别主线程和从线程的操作\n    主套接字描述符准备就绪，使用主线程的操作\n    从套接字的描述符就绪，使用从线程的操作\n</code></pre>\n"}]}]},{"t":"list_item","d":5,"p":{},"v":"Select原理","c":[{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">Select调用时，根据描述符集中被设置的位得到描述符值，进而找到对应的套接字结构，看是否有数据就绪（读<span class=\"token operator\">/</span>写<span class=\"token operator\">/</span>异常就绪），没有就绪的描述符在描述符集中对应位就被清<span class=\"token number\">0</span>，所以每次调用select前都要将我们所关心的描述符在描述符集中置<span class=\"token number\">1.</span>\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"select返回描述符集中已经准备好的总位数。"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\"><span class=\"token keyword\">int</span> <span class=\"token function\">select</span><span class=\"token punctuation\">(</span>nfds<span class=\"token punctuation\">,</span> readfds<span class=\"token punctuation\">,</span> writefds<span class=\"token punctuation\">,</span> exceptfds<span class=\"token punctuation\">,</span> timeout<span class=\"token punctuation\">)</span> <span class=\"token keyword\">int</span> nfds<span class=\"token punctuation\">;</span>\nfd_set <span class=\"token operator\">*</span>readfds<span class=\"token punctuation\">,</span> <span class=\"token operator\">*</span>writefds<span class=\"token punctuation\">,</span> <span class=\"token operator\">*</span>exceptfds<span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">struct</span> <span class=\"token class-name\">timeval</span> <span class=\"token operator\">*</span>timeout<span class=\"token punctuation\">;</span>\n<span class=\"token comment\">/*\nndfs：select监视的文件句柄数，视进程中打开的文件数而定,一般设为呢要监视各文件中的最大文件号加一。 \nreadfds：select监视的可读文件句柄集合。 \nwritefds: select监视的可写文件句柄集合。 \nexceptfds：select监视的异常文件句柄集合。 \ntimeout：本次select()的超时结束时间。（见/usr/sys/select.h，可精确至百万分之一秒！）\n*/</span>\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">几只相关的宏解释如下： \n<span class=\"token function\">FD_ZERO</span><span class=\"token punctuation\">(</span>fd_set <span class=\"token operator\">*</span>fdset<span class=\"token punctuation\">)</span>：清空fdset与所有文件句柄的联系。 \n<span class=\"token function\">FD_SET</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> fd<span class=\"token punctuation\">,</span> fd_set <span class=\"token operator\">*</span>fdset<span class=\"token punctuation\">)</span>：建立文件句柄fd与fdset的联系。 <span class=\"token function\">FD_CLR</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> fd<span class=\"token punctuation\">,</span> fd_set <span class=\"token operator\">*</span>fdset<span class=\"token punctuation\">)</span>：清除文件句柄fd与fdset的联系。 <span class=\"token function\">FD_ISSET</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> fd<span class=\"token punctuation\">,</span> fdset <span class=\"token operator\">*</span>fdset<span class=\"token punctuation\">)</span>：检查fdset联系的文件句柄fd是否可读写，<span class=\"token operator\">></span><span class=\"token number\">0</span>表示可读写。\n</code></pre>\n"},{"t":"list_item","d":7,"p":{},"v":"<pre class=\"language-c\"><code class=\"language-c\">TCPmechod<span class=\"token punctuation\">.</span>c    page118\n在熟知端口上打开一个被动套接字\n使用系统函数getdtablesize来决定描述符最大个数\n使用FD_ZERO和FD_SET创建一个比特向量，对应于希望测试的套接字描述符\nselect等待一个或者多个描述符就绪\nFD_ISSET测试哪个描述符就绪\nFD_CLR关闭连接后，从描述符组中删除\n</code></pre>\n"}]}]},{"t":"bullet_list","d":4,"p":{},"v":"","c":[{"t":"list_item","d":5,"p":{},"v":"poll性能比select好，select移植性好"}]}]}]}]})</script>
</body>
</html>
